From 394737eb4202844b6501851d7c8588164d370060 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 15 Oct 2006 00:34:47 -0700 Subject: [PATCH 0001/3720] pack-objects: use of version 3 delta is now optional. This introduces a new configuration item, pack.deltaversion, to control whether pack-objects is allowed to use version 3 delta. By default, we keep generating version 2 delta (and version 2 packfile format) to be compatible with git earlier than v1.2.0. This configuration affects the command in the following ways: - the resulting packfile will have the specified version; - when generating delta, larger copies are allowed only when deltaversion is 3; - the logic to reuse delta from existing packs refuses to reuse delta from packs that uses delta version 3 when the configuration is set to 2. Signed-off-by: Junio C Hamano --- builtin-pack-objects.c | 17 +++++++++++++---- cache.h | 1 + delta.h | 2 ++ diff-delta.c | 15 +++++++++++++-- environment.c | 3 +++ sha1_file.c | 1 + 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 96c069a81d..3532dc8557 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -456,7 +456,7 @@ static void write_pack_file(void) fprintf(stderr, "Writing %d objects.\n", nr_result); hdr.hdr_signature = htonl(PACK_SIGNATURE); - hdr.hdr_version = htonl(PACK_VERSION); + hdr.hdr_version = htonl(delta_version); hdr.hdr_entries = htonl(nr_result); sha1write(f, &hdr, sizeof(hdr)); offset = sizeof(hdr); @@ -914,12 +914,15 @@ static void check_object(struct object_entry *entry) /* Check if it is delta, and the base is also an object * we are going to pack. If so we will reuse the existing * delta. + * + * Also make sure that we do not reuse delta from an existing + * pack that uses higher delta version than allowed. */ if (!no_reuse_delta && entry->in_pack_type == OBJ_DELTA && (base_entry = locate_object_entry(base)) && - (!base_entry->preferred_base)) { - + (!base_entry->preferred_base) && + entry->in_pack->pack_version <= delta_version) { /* Depth value does not matter - find_deltas() * will never consider reused delta as the * base object to deltify other objects @@ -1101,6 +1104,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, * on an earlier try, but only when reusing delta data. */ if (!no_reuse_delta && trg_entry->in_pack && + trg_entry->in_pack->pack_version <= delta_version && trg_entry->in_pack == src_entry->in_pack) return 0; @@ -1326,10 +1330,15 @@ static void setup_progress_signal(void) static int git_pack_config(const char *k, const char *v) { - if(!strcmp(k, "pack.window")) { + if (!strcmp(k, "pack.window")) { window = git_config_int(k, v); return 0; } + if (!strcmp(k, "pack.deltaversion")) { + delta_version = git_config_int(k, v); + if (!pack_version_ok(htonl(delta_version))) + die("value %s for '%s' not allowed", v, k); + } return git_default_config(k, v); } diff --git a/cache.h b/cache.h index c35470107d..724c09ae4f 100644 --- a/cache.h +++ b/cache.h @@ -337,6 +337,7 @@ extern struct packed_git { unsigned int pack_last_used; unsigned int pack_use_cnt; int pack_local; + int pack_version; unsigned char sha1[20]; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ diff --git a/delta.h b/delta.h index 7b3f86d85f..55af3d285e 100644 --- a/delta.h +++ b/delta.h @@ -1,6 +1,8 @@ #ifndef DELTA_H #define DELTA_H +extern int delta_version; + /* opaque object for delta index */ struct delta_index; diff --git a/diff-delta.c b/diff-delta.c index fa16d06c8d..2f6dcfb0d7 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -253,10 +253,13 @@ create_delta(const struct delta_index *index, int inscnt; const unsigned char *ref_data, *ref_top, *data, *top; unsigned char *out; + unsigned int ref_size_limit; if (!trg_buf || !trg_size) return NULL; + ref_size_limit = (delta_version > 2) ? 0xffffff : 0x10000; + outpos = 0; outsize = 8192; if (max_size && outsize >= max_size) @@ -308,8 +311,8 @@ create_delta(const struct delta_index *index, continue; if (ref_size > top - src) ref_size = top - src; - if (ref_size > 0x10000) - ref_size = 0x10000; + if (ref_size > ref_size_limit) + ref_size = ref_size_limit; if (ref_size <= msize) break; while (ref_size-- && *src++ == *ref) @@ -318,6 +321,8 @@ create_delta(const struct delta_index *index, /* this is our best match so far */ msize = ref - entry->ptr; moff = entry->ptr - ref_data; + if (delta_version > 2 && msize >= 0x10000) + break; /* this is good enough */ } } @@ -381,6 +386,12 @@ create_delta(const struct delta_index *index, if (msize & 0xff) { out[outpos++] = msize; i |= 0x10; } msize >>= 8; if (msize & 0xff) { out[outpos++] = msize; i |= 0x20; } + if (delta_version > 2) { + msize >>= 8; + if (msize & 0xff) { + out[outpos++] = msize; i |= 0x40; + } + } *op = i; } diff --git a/environment.c b/environment.c index 63b1d155be..e266f83a8e 100644 --- a/environment.c +++ b/environment.c @@ -8,6 +8,7 @@ * are. */ #include "cache.h" +#include "pack.h" char git_default_email[MAX_GITNAME]; char git_default_name[MAX_GITNAME]; @@ -25,6 +26,8 @@ const char *apply_default_whitespace; int zlib_compression_level = Z_DEFAULT_COMPRESSION; int pager_in_use; int pager_use_color = 1; +/* by default we allow 2 but up to PACK_VERSION is allowed */ +int delta_version = 2; static const char *git_dir; static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; diff --git a/sha1_file.c b/sha1_file.c index d111be74a3..665318243c 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -527,6 +527,7 @@ int use_packed_git(struct packed_git *p) p->pack_size - 20)) { die("packfile %s does not match index.", p->pack_name); } + p->pack_version = ntohl(hdr->hdr_version); } p->pack_last_used = pack_used_ctr++; p->pack_use_cnt++; From 69a4752063748932d26901fe1aca61381d381a7d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 15 Oct 2006 12:28:58 -0700 Subject: [PATCH 0002/3720] Revert "pack-objects: use of version 3 delta is now optional." This reverts commit 394737eb4202844b6501851d7c8588164d370060. Saving a few bytes per every 64kB of delta copied is not worth, when compared with the cost of backward compatibility worries. --- builtin-pack-objects.c | 17 ++++------------- cache.h | 1 - delta.h | 2 -- diff-delta.c | 15 ++------------- environment.c | 3 --- sha1_file.c | 1 - 6 files changed, 6 insertions(+), 33 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 3532dc8557..96c069a81d 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -456,7 +456,7 @@ static void write_pack_file(void) fprintf(stderr, "Writing %d objects.\n", nr_result); hdr.hdr_signature = htonl(PACK_SIGNATURE); - hdr.hdr_version = htonl(delta_version); + hdr.hdr_version = htonl(PACK_VERSION); hdr.hdr_entries = htonl(nr_result); sha1write(f, &hdr, sizeof(hdr)); offset = sizeof(hdr); @@ -914,15 +914,12 @@ static void check_object(struct object_entry *entry) /* Check if it is delta, and the base is also an object * we are going to pack. If so we will reuse the existing * delta. - * - * Also make sure that we do not reuse delta from an existing - * pack that uses higher delta version than allowed. */ if (!no_reuse_delta && entry->in_pack_type == OBJ_DELTA && (base_entry = locate_object_entry(base)) && - (!base_entry->preferred_base) && - entry->in_pack->pack_version <= delta_version) { + (!base_entry->preferred_base)) { + /* Depth value does not matter - find_deltas() * will never consider reused delta as the * base object to deltify other objects @@ -1104,7 +1101,6 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, * on an earlier try, but only when reusing delta data. */ if (!no_reuse_delta && trg_entry->in_pack && - trg_entry->in_pack->pack_version <= delta_version && trg_entry->in_pack == src_entry->in_pack) return 0; @@ -1330,15 +1326,10 @@ static void setup_progress_signal(void) static int git_pack_config(const char *k, const char *v) { - if (!strcmp(k, "pack.window")) { + if(!strcmp(k, "pack.window")) { window = git_config_int(k, v); return 0; } - if (!strcmp(k, "pack.deltaversion")) { - delta_version = git_config_int(k, v); - if (!pack_version_ok(htonl(delta_version))) - die("value %s for '%s' not allowed", v, k); - } return git_default_config(k, v); } diff --git a/cache.h b/cache.h index 724c09ae4f..c35470107d 100644 --- a/cache.h +++ b/cache.h @@ -337,7 +337,6 @@ extern struct packed_git { unsigned int pack_last_used; unsigned int pack_use_cnt; int pack_local; - int pack_version; unsigned char sha1[20]; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ diff --git a/delta.h b/delta.h index 55af3d285e..7b3f86d85f 100644 --- a/delta.h +++ b/delta.h @@ -1,8 +1,6 @@ #ifndef DELTA_H #define DELTA_H -extern int delta_version; - /* opaque object for delta index */ struct delta_index; diff --git a/diff-delta.c b/diff-delta.c index 2f6dcfb0d7..fa16d06c8d 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -253,13 +253,10 @@ create_delta(const struct delta_index *index, int inscnt; const unsigned char *ref_data, *ref_top, *data, *top; unsigned char *out; - unsigned int ref_size_limit; if (!trg_buf || !trg_size) return NULL; - ref_size_limit = (delta_version > 2) ? 0xffffff : 0x10000; - outpos = 0; outsize = 8192; if (max_size && outsize >= max_size) @@ -311,8 +308,8 @@ create_delta(const struct delta_index *index, continue; if (ref_size > top - src) ref_size = top - src; - if (ref_size > ref_size_limit) - ref_size = ref_size_limit; + if (ref_size > 0x10000) + ref_size = 0x10000; if (ref_size <= msize) break; while (ref_size-- && *src++ == *ref) @@ -321,8 +318,6 @@ create_delta(const struct delta_index *index, /* this is our best match so far */ msize = ref - entry->ptr; moff = entry->ptr - ref_data; - if (delta_version > 2 && msize >= 0x10000) - break; /* this is good enough */ } } @@ -386,12 +381,6 @@ create_delta(const struct delta_index *index, if (msize & 0xff) { out[outpos++] = msize; i |= 0x10; } msize >>= 8; if (msize & 0xff) { out[outpos++] = msize; i |= 0x20; } - if (delta_version > 2) { - msize >>= 8; - if (msize & 0xff) { - out[outpos++] = msize; i |= 0x40; - } - } *op = i; } diff --git a/environment.c b/environment.c index e266f83a8e..63b1d155be 100644 --- a/environment.c +++ b/environment.c @@ -8,7 +8,6 @@ * are. */ #include "cache.h" -#include "pack.h" char git_default_email[MAX_GITNAME]; char git_default_name[MAX_GITNAME]; @@ -26,8 +25,6 @@ const char *apply_default_whitespace; int zlib_compression_level = Z_DEFAULT_COMPRESSION; int pager_in_use; int pager_use_color = 1; -/* by default we allow 2 but up to PACK_VERSION is allowed */ -int delta_version = 2; static const char *git_dir; static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; diff --git a/sha1_file.c b/sha1_file.c index 665318243c..d111be74a3 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -527,7 +527,6 @@ int use_packed_git(struct packed_git *p) p->pack_size - 20)) { die("packfile %s does not match index.", p->pack_name); } - p->pack_version = ntohl(hdr->hdr_version); } p->pack_last_used = pack_used_ctr++; p->pack_use_cnt++; From 0edad44201d9edf4c7d4640c8af9212e3ee23da9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 4 Nov 2006 12:24:05 -0800 Subject: [PATCH 0003/3720] adjust_shared_perm: chmod() only when needed. When widening permission for files and directories in a 'shared' repository for a user with inappropriate umask() setting for shared work, make sure we call chmod() only when we actually need to. The primary idea owes credit to Johannes. Signed-off-by: Junio C Hamano --- path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/path.c b/path.c index bb89fb02dc..d2c076d7cb 100644 --- a/path.c +++ b/path.c @@ -279,7 +279,7 @@ int adjust_shared_perm(const char *path) : 0)); if (S_ISDIR(mode)) mode |= S_ISGID; - if (chmod(path, mode) < 0) + if ((mode & st.st_mode) != mode && chmod(path, mode) < 0) return -2; return 0; } From a2a92ab17fe120f6b28d123ac2fd41f066f0de1e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 29 Nov 2006 18:53:13 -0800 Subject: [PATCH 0004/3720] git-merge: preserve and merge local changes when doing fast forward The idea and the logic are identical to what "checkout -m" does when switching the branches. Instead of refusing the two-way merge, perform the three-way merge between the old head, the working tree and the new head, and leave the (potentially conflicted) merge result in the working tree. When the resulting conflict were too much to handle for the user, there is no easy way to get that back, so they are stashed away in $GIT_DIR/LOCAL_DIFF file. We do the same for "git checkout -m". If this turns out to be a sane thing to do, we probably should make the common logic between "checkout -m" and this into a built-in command. Signed-off-by: Junio C Hamano --- git-checkout.sh | 7 +++++++ git-merge.sh | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/git-checkout.sh b/git-checkout.sh index 737abd0c09..5bf399a276 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -168,6 +168,9 @@ else exit 1 ;; esac + # First stash away the local changes + git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF + # Match the index to the working tree, and do a three-way. git diff-files --name-only | git update-index --remove --stdin && work=`git write-tree` && @@ -195,6 +198,10 @@ else sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" echo "$unmerged" ) | git update-index --index-info + + echo >&2 "Conflicts in locally modified files:" + git diff --name-only --diff-filter=U >&2 + echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF" ;; esac exit 0 diff --git a/git-merge.sh b/git-merge.sh index 272f004622..798aad3576 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -91,6 +91,51 @@ finish () { esac } +merge_local_changes () { + merge_error=$(git-read-tree -m -u $1 $2 2>&1) || ( + + # First stash away the local changes + git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF + + # Match the index to the working tree, and do a three-way. + git diff-files --name-only | + git update-index --remove --stdin && + work=`git write-tree` && + git read-tree --reset -u $2 && + git read-tree -m -u --aggressive $1 $2 $work || exit + + echo >&2 "Carrying local changes forward." + if result=`git write-tree 2>/dev/null` + then + echo >&2 "Trivially automerged." + else + git merge-index -o git-merge-one-file -a + fi + + # Do not register the cleanly merged paths in the index + # yet; this is not a real merge before committing, but + # just carrying the working tree changes along. + unmerged=`git ls-files -u` + git read-tree --reset $2 + case "$unmerged" in + '') ;; + *) + ( + z40=0000000000000000000000000000000000000000 + echo "$unmerged" | + sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" + echo "$unmerged" + ) | git update-index --index-info + + echo >&2 "Conflicts in locally modified files:" + git diff --name-only --diff-filter=U >&2 + echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF" + ;; + esac + exit 0 + ) +} + case "$#" in 0) usage ;; esac rloga= have_message= @@ -264,7 +309,7 @@ f,*) echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)" git-update-index --refresh 2>/dev/null new_head=$(git-rev-parse --verify "$1^0") && - git-read-tree -u -v -m $head "$new_head" && + merge_local_changes $head $new_head && finish "$new_head" "Fast forward" dropsave exit 0 From 40e0e66bb00646fbdc998c4fe01280470489d0e5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 8 Jan 2007 23:26:19 -0800 Subject: [PATCH 0005/3720] merge_base(): move traversal into a separate function. Signed-off-by: Junio C Hamano --- commit.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/commit.c b/commit.c index aa14c5adb0..53f43e3638 100644 --- a/commit.c +++ b/commit.c @@ -1034,25 +1034,10 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *merge_bases(struct commit *one, struct commit *two) +static struct commit_list *base_traverse(struct commit_list *list) { - struct commit_list *list = NULL; struct commit_list *result = NULL; - if (one == two) - /* We do not mark this even with RESULT so we do not - * have to clean it up. - */ - return commit_list_insert(one, &result); - - parse_commit(one); - parse_commit(two); - - one->object.flags |= PARENT1; - two->object.flags |= PARENT2; - insert_by_date(one, &list); - insert_by_date(two, &list); - while (interesting(list)) { struct commit *commit; struct commit_list *parents; @@ -1098,6 +1083,27 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two) return result; } +static struct commit_list *merge_bases(struct commit *one, struct commit *two) +{ + struct commit_list *list = NULL; + + if (one == two) + /* We do not mark this even with RESULT so we do not + * have to clean it up. + */ + return commit_list_insert(one, &list); + + parse_commit(one); + parse_commit(two); + + one->object.flags |= PARENT1; + two->object.flags |= PARENT2; + insert_by_date(one, &list); + insert_by_date(two, &list); + + return base_traverse(list); +} + struct commit_list *get_merge_bases(struct commit *one, struct commit *two, int cleanup) From dc3806d39698899fe81e55c0daa5bd9d30d13d9c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 9 Jan 2007 01:32:25 -0800 Subject: [PATCH 0006/3720] in_merge_bases(): optimization The callers of in_merge_bases() are interested in finding out if the given commit is reachable from others, and we do not have to compute the true merge base. Signed-off-by: Junio C Hamano --- commit.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/commit.c b/commit.c index 53f43e3638..bbfe7dc686 100644 --- a/commit.c +++ b/commit.c @@ -1034,7 +1034,7 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *base_traverse(struct commit_list *list) +static struct commit_list *base_traverse(struct commit_list *list, struct commit *stop) { struct commit_list *result = NULL; @@ -1068,10 +1068,20 @@ static struct commit_list *base_traverse(struct commit_list *list) p->object.flags |= flags; insert_by_date(p, &list); } + if (stop && (stop->object.flags & PARENT2)) { + free_commit_list(list); + list = NULL; + insert_by_date(stop, &list); + return list; + } } /* Clean up the result to remove stale ones */ free_commit_list(list); + + if (stop) + return NULL; + list = result; result = NULL; while (list) { struct commit_list *n = list->next; @@ -1101,7 +1111,7 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two) insert_by_date(one, &list); insert_by_date(two, &list); - return base_traverse(list); + return base_traverse(list, NULL); } struct commit_list *get_merge_bases(struct commit *one, @@ -1166,20 +1176,30 @@ struct commit_list *get_merge_bases(struct commit *one, int in_merge_bases(struct commit *commit, struct commit **reference, int num) { - struct commit_list *bases, *b; - int ret = 0; + struct commit_list *result, *list; + int i, ret; - if (num == 1) - bases = get_merge_bases(commit, *reference, 1); - else - die("not yet"); - for (b = bases; b; b = b->next) { - if (!hashcmp(commit->object.sha1, b->item->object.sha1)) { - ret = 1; - break; + list = NULL; + parse_commit(commit); + commit->object.flags |= PARENT1; + insert_by_date(commit, &list); + + for (i = 0; i < num; i++) { + struct commit *two = reference[i]; + parse_commit(two); + if (!(two->object.flags & PARENT2)) { + two->object.flags |= PARENT2; + insert_by_date(two, &list); } } + result = base_traverse(list, commit); + ret = !!result; + free_commit_list(result); - free_commit_list(bases); + clear_commit_marks(commit, all_flags); + for (i = 0; i < num; i++) { + struct commit *two = reference[i]; + clear_commit_marks(two, all_flags); + } return ret; } From cdea3553ef02b463afb66c4251b8574ba1365ede Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:36:47 +0100 Subject: [PATCH 0007/3720] Split the big verify-pack test into individual tests. This makes it easier to spot which of the tests failed. --- t/t5300-pack-object.sh | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index f511547455..622c5f9968 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -134,49 +134,51 @@ test_expect_success \ 'git-verify-pack test-1-${packname_1}.idx test-2-${packname_2}.idx' test_expect_success \ - 'corrupt a pack and see if verify catches' \ + 'verify-pack catches mismatched .idx and .pack files' \ 'cp test-1-${packname_1}.idx test-3.idx && cp test-2-${packname_2}.pack test-3.pack && if git-verify-pack test-3.idx then false else :; - fi && + fi' - : PACK_SIGNATURE && - cp test-1-${packname_1}.pack test-3.pack && +test_expect_success \ + 'verify-pack catches a corrupted pack signature' \ + 'cp test-1-${packname_1}.pack test-3.pack && dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=2 && if git-verify-pack test-3.idx then false else :; - fi && + fi' - : PACK_VERSION && - cp test-1-${packname_1}.pack test-3.pack && +test_expect_success \ + 'verify-pack catches a corrupted pack version' \ + 'cp test-1-${packname_1}.pack test-3.pack && dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=7 && if git-verify-pack test-3.idx then false else :; - fi && + fi' - : TYPE/SIZE byte of the first packed object data && - cp test-1-${packname_1}.pack test-3.pack && +test_expect_success \ + 'verify-pack catches a corrupted type/size of the 1st packed object data' \ + 'cp test-1-${packname_1}.pack test-3.pack && dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=12 && if git-verify-pack test-3.idx then false else :; - fi && + fi' - : sum of the index file itself && - l=`wc -c Date: Thu, 18 Jan 2007 11:21:30 +0100 Subject: [PATCH 0008/3720] Lose perl dependency. Perl is just used to reverse stdin, which can be done with a simple sed construct as well. Signed-off-by: Simon 'corecode' Schubert --- git-rebase.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-rebase.sh b/git-rebase.sh index c8bd0f99d1..c34a0d2fc5 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -332,7 +332,7 @@ echo "$prev_head" > "$dotest/prev_head" msgnum=0 for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \ - | @@PERL@@ -e 'print reverse <>'` + | sed -ne '1!G;$p;h'` do msgnum=$(($msgnum + 1)) echo "$cmt" > "$dotest/cmt.$msgnum" From 9983977758b00215f93ec636f009df5312a74537 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 16 Jan 2007 16:35:34 +0100 Subject: [PATCH 0009/3720] Move the revision walker into a separate function. --- upload-pack.c | 70 +++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 3a466c6a3e..0ce8ceeeac 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -96,6 +96,42 @@ static void show_edge(struct commit *commit) fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1)); } +static void do_rev_list(int create_full_pack) +{ + int i; + struct rev_info revs; + + if (create_full_pack) + use_thin_pack = 0; /* no point doing it */ + init_revisions(&revs, NULL); + revs.tag_objects = 1; + revs.tree_objects = 1; + revs.blob_objects = 1; + if (use_thin_pack) + revs.edge_hint = 1; + + if (create_full_pack) { + const char *args[] = {"rev-list", "--all", NULL}; + setup_revisions(2, args, &revs, NULL); + } else { + for (i = 0; i < want_obj.nr; i++) { + struct object *o = want_obj.objects[i].item; + /* why??? */ + o->flags &= ~UNINTERESTING; + add_pending_object(&revs, o, NULL); + } + for (i = 0; i < have_obj.nr; i++) { + struct object *o = have_obj.objects[i].item; + o->flags |= UNINTERESTING; + add_pending_object(&revs, o, NULL); + } + setup_revisions(0, NULL, &revs, NULL); + } + prepare_revision_walk(&revs); + mark_edges_uninteresting(revs.commits, &revs, show_edge); + traverse_commit_list(&revs, show_commit, show_object); +} + static void create_pack_file(void) { /* Pipes between rev-list to pack-objects, pack-objects to us @@ -116,40 +152,8 @@ static void create_pack_file(void) die("git-upload-pack: unable to fork git-rev-list"); if (!pid_rev_list) { - int i; - struct rev_info revs; - pack_pipe = fdopen(lp_pipe[1], "w"); - - if (create_full_pack) - use_thin_pack = 0; /* no point doing it */ - init_revisions(&revs, NULL); - revs.tag_objects = 1; - revs.tree_objects = 1; - revs.blob_objects = 1; - if (use_thin_pack) - revs.edge_hint = 1; - - if (create_full_pack) { - const char *args[] = {"rev-list", "--all", NULL}; - setup_revisions(2, args, &revs, NULL); - } else { - for (i = 0; i < want_obj.nr; i++) { - struct object *o = want_obj.objects[i].item; - /* why??? */ - o->flags &= ~UNINTERESTING; - add_pending_object(&revs, o, NULL); - } - for (i = 0; i < have_obj.nr; i++) { - struct object *o = have_obj.objects[i].item; - o->flags |= UNINTERESTING; - add_pending_object(&revs, o, NULL); - } - setup_revisions(0, NULL, &revs, NULL); - } - prepare_revision_walk(&revs); - mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, show_object); + do_rev_list(create_full_pack); exit(0); } From 14cd93911230bc2306d548eb7393f01a36d801b4 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 22 Dec 2006 11:43:50 +0100 Subject: [PATCH 0010/3720] Make git compile under MinGW. These changes are courtesy Johannes Schindelin. --- Makefile | 24 +++++- builtin-count-objects.c | 4 + compat/mingw.c | 164 ++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 108 ++++++++++++++++++++++++-- help.c | 2 +- ident.c | 22 ++++++ path.c | 11 +++ 7 files changed, 324 insertions(+), 11 deletions(-) create mode 100644 compat/mingw.c diff --git a/Makefile b/Makefile index 963a8f64e9..64d7f49019 100644 --- a/Makefile +++ b/Makefile @@ -192,9 +192,8 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ # ... and all the rest that could be moved out of bindir to gitexecdir PROGRAMS = \ - git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \ + git-fetch-pack$X git-fsck-objects$X \ git-hash-object$X git-index-pack$X git-local-fetch$X \ - git-daemon$X \ git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \ git-peek-remote$X git-receive-pack$X \ git-send-pack$X git-shell$X \ @@ -203,7 +202,7 @@ PROGRAMS = \ git-update-server-info$X \ git-upload-pack$X git-verify-pack$X \ git-pack-redundant$X git-var$X \ - git-merge-tree$X git-imap-send$X \ + git-merge-tree$X \ git-merge-recursive$X \ $(EXTRA_PROGRAMS) @@ -412,6 +411,25 @@ ifeq ($(uname_S),IRIX64) # for now, build 32-bit version BASIC_LDFLAGS += -L/usr/lib32 endif +ifneq (,$(findstring MINGW,$(uname_S))) + SHELL_PATH = $(shell cd /bin && pwd -W)/sh + NO_MMAP=YesPlease + NO_PREAD=YesPlease + NO_OPENSSL=YesPlease + NO_CURL=YesPlease + NO_SYMLINK_HEAD=YesPlease + NO_IPV6=YesPlease + NO_ETC_PASSWD=YesPlease + NO_SETENV=YesPlease + NO_UNSETENV=YesPlease + NO_STRCASESTR=YesPlease + NO_STRLCPY=YesPlease + NO_ICONV=YesPlease + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS + COMPAT_OBJS += compat/mingw.o + EXTLIBS += -lws2_32 + X = .exe +endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease endif diff --git a/builtin-count-objects.c b/builtin-count-objects.c index f5b22bb80e..a2df569a0d 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -44,7 +44,11 @@ static void count_objects(DIR *d, char *path, int len, int verbose, if (lstat(path, &st) || !S_ISREG(st.st_mode)) bad = 1; else +#ifndef NO_ST_BLOCKS (*loose_size) += st.st_blocks; +#else + (*loose_size) += (st.st_size+511)/512; +#endif } if (bad) { if (verbose) { diff --git a/compat/mingw.c b/compat/mingw.c new file mode 100644 index 0000000000..0f7077983f --- /dev/null +++ b/compat/mingw.c @@ -0,0 +1,164 @@ +#include +#include "../git-compat-util.h" + +int readlink(const char *path, char *buf, size_t bufsiz) +{ + errno = EINVAL; + return -1; +} + +int symlink(const char *oldpath, const char *newpath) +{ + errno = EFAULT; + return -1; +} + +int fchmod(int fildes, mode_t mode) +{ + errno = EBADF; + return -1; +} + +int lstat(const char *file_name, struct stat *buf) +{ + return stat(file_name, buf); +} + +/* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ +int socketpair(int d, int type, int protocol, int sv[2]) +{ + return -1; +} +int syslog(int type, char *bufp, ...) +{ + return -1; +} +unsigned int alarm(unsigned int seconds) +{ + return 0; +} +#include +int fork() +{ + return -1; +} +typedef int pid_t; +pid_t waitpid(pid_t pid, int *status, int options) +{ + errno = ECHILD; + return -1; +} + +int kill(pid_t pid, int sig) +{ + return -1; +} +int sigaction(int p1, const struct sigaction *p2, struct sigaction *p3) +{ + return -1; +} +int sigemptyset(sigset_t *p1) +{ + return -1; +} +int setitimer(int __which, const struct itimerval *__value, + struct itimerval *__ovalue) +{ + return -1; +} +unsigned int sleep (unsigned int __seconds) +{ + return 0; +} +const char *inet_ntop(int af, const void *src, + char *dst, size_t cnt) +{ + return NULL; +} +int mkstemp (char *__template) +{ + return -1; +} +int gettimeofday(struct timeval *tv, void *tz) +{ + return -1; +} +int pipe(int filedes[2]) +{ + return -1; +} + +int poll(struct pollfd *ufds, unsigned int nfds, int timeout) +{ + return -1; +} + +int fnmatch(const char *pattern, const char *string, int flags) +{ + return -1; +} + +int regcomp(regex_t *preg, const char *regex, int cflags) +{ + return -1; +} +size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) +{ + return 0; +} +void regfree(regex_t *preg) +{ +} + +int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) +{ + return -1; +} + +#undef mkdir +int git_mkdir(const char *path, int mode) +{ + return mkdir(path); +} + +#include + +struct tm *gmtime_r(const time_t *timep, struct tm *result) +{ + memcpy(result, gmtime(timep), sizeof(struct tm)); + return result; +} + +struct tm *localtime_r(const time_t *timep, struct tm *result) +{ + memcpy(result, localtime(timep), sizeof(struct tm)); + return result; +} + +#undef getcwd +char *mingw_getcwd(char *pointer, int len) +{ + char *ret = getcwd(pointer, len); + if (!ret) + return ret; + if (pointer[0] != 0 && pointer[1] == ':') { + int i; + pointer[1] = pointer[0]; + pointer[0] = '/'; + for (i = 2; pointer[i]; i++) + /* Thanks, Bill. You'll burn in hell for that. */ + if (pointer[i] == '\\') + pointer[i] = '/'; + } + return ret; +} +const char *strptime(char *buf, const char *format, struct tm *tm) +{ + die("MinGW does not yet support strptime!"); +} +void sync(void) +{ +} +void openlog(const char *ident, int option, int facility) +{ +} diff --git a/git-compat-util.h b/git-compat-util.h index bf3ceb8027..2bdae6725d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -35,21 +35,23 @@ #include #include #include -#include -#include -#include -#include +//#include +//#include +//#include +//#include #include #include -#include -#include -#include +//#include +//#include +//#include +#ifndef NO_ETC_PASSWD #include #include #include #undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */ #include #define _ALL_SOURCE 1 +#endif #ifndef NO_ICONV #include @@ -271,4 +273,96 @@ static inline int sane_case(int x, int high) return x; } +// MinGW + +#ifndef S_ISLNK +#define S_ISLNK(x) 0 +#define S_IFLNK 0 +#endif + +#ifndef S_ISGRP +#define S_ISGRP(x) 0 +#define S_IRGRP 0 +#define S_IWGRP 0 +#define S_IXGRP 0 +#define S_ISGID 0 +#define S_IROTH 0 +#define S_IXOTH 0 +#endif + +int readlink(const char *path, char *buf, size_t bufsiz); +int symlink(const char *oldpath, const char *newpath); +#define link symlink +int fchmod(int fildes, mode_t mode); +int lstat(const char *file_name, struct stat *buf); + +/* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ +int socketpair(int d, int type, int protocol, int sv[2]); +#define AF_UNIX 0 +#define SOCK_STREAM 0 +int syslog(int type, char *bufp, ...); +#define LOG_ERR 1 +#define LOG_INFO 2 +#define LOG_DAEMON 4 +unsigned int alarm(unsigned int seconds); +#include +int fork(); +typedef int pid_t; +pid_t waitpid(pid_t pid, int *status, int options); +#define WIFEXITED(x) 0 +#define WEXITSTATUS(x) 1 +#define WIFSIGNALED(x) -1 +#define WTERMSIG(x) 0 +#define WNOHANG 0 +#define SIGKILL 0 +#define SIGCHLD 0 +#define SIGALRM 0 +#define ECONNABORTED 0 + +int kill(pid_t pid, int sig); +unsigned int sleep (unsigned int __seconds); +const char *inet_ntop(int af, const void *src, + char *dst, size_t cnt); +int mkstemp (char *__template); +int gettimeofday(struct timeval *tv, void *tz); +int pipe(int filedes[2]); + +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; +int poll(struct pollfd *ufds, unsigned int nfds, int timeout); +#define POLLIN 1 +#define POLLHUP 2 +int fnmatch(const char *pattern, const char *string, int flags); +#define FNM_PATHNAME 1 + +typedef int siginfo_t; +struct sigaction { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; +#define SA_RESTART 0 +#define ITIMER_REAL 0 + +struct itimerval { struct timeval it_interval, it_value; }; + +int git_mkdir(const char *path, int mode); +#define mkdir git_mkdir + +#include +struct tm *gmtime_r(const time_t *timep, struct tm *result); +struct tm *localtime_r(const time_t *timep, struct tm *result); +#define hstrerror strerror + +char *mingw_getcwd(char *pointer, int len); +#define getcwd mingw_getcwd + +#define setlinebuf(x) +#define fsync(x) + #endif diff --git a/help.c b/help.c index 341b9e370e..2f7ef39661 100644 --- a/help.c +++ b/help.c @@ -7,7 +7,7 @@ #include "builtin.h" #include "exec_cmd.h" #include "common-cmds.h" -#include +//#include /* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) diff --git a/ident.c b/ident.c index 6ad8fedd60..83ce631a06 100644 --- a/ident.c +++ b/ident.c @@ -9,6 +9,8 @@ static char git_default_date[50]; +#ifndef NO_ETC_PASSWD + static void copy_gecos(struct passwd *w, char *name, int sz) { char *src, *dst; @@ -77,6 +79,8 @@ int setup_ident(void) return 0; } +#else /* NO_ETC_PASSWD */ + static int add_raw(char *buf, int size, int offset, const char *str) { int len = strlen(str); @@ -152,6 +156,13 @@ static int copy(char *buf, int size, int offset, const char *src) return offset; } +int setup_ident(void) +{ + return 0; +} + +#endif + static const char au_env[] = "GIT_AUTHOR_NAME"; static const char co_env[] = "GIT_COMMITTER_NAME"; static const char *env_hint = @@ -219,6 +230,8 @@ const char *git_committer_info(int error_on_no_name) error_on_no_name); } +#ifndef NO_ETC_PASSWD + void ignore_missing_committer_name() { /* If we did not get a name from the user's gecos entry then @@ -233,3 +246,12 @@ void ignore_missing_committer_name() strlcpy(git_default_name, pw->pw_name, sizeof(git_default_name)); } } + +#else + +void ignore_missing_committer_name() +{ + strcpy(git_default_name, "unknown"); +} + +#endif diff --git a/path.c b/path.c index c5d25a4b90..d66d6a1ec1 100644 --- a/path.c +++ b/path.c @@ -140,6 +140,8 @@ int validate_headref(const char *path) return -1; } +#ifndef NO_ETC_PASSWD + static char *user_path(char *buf, char *path, int sz) { struct passwd *pw; @@ -179,6 +181,15 @@ static char *user_path(char *buf, char *path, int sz) return buf; } +#else + +static char *user_path(char *buf, char *path, int sz) +{ + return getenv("HOME"); +} + +#endif + /* * First, one directory to try is determined by the following algorithm. * From 65e40a61951a62393ec474724d7ffad677afa57e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 15:38:36 +0200 Subject: [PATCH 0011/3720] Provide inlined mkdir wrapper. --- compat/mingw.c | 6 ------ git-compat-util.h | 5 ++++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0f7077983f..f85b0d2f52 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -115,12 +115,6 @@ int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t p return -1; } -#undef mkdir -int git_mkdir(const char *path, int mode) -{ - return mkdir(path); -} - #include struct tm *gmtime_r(const time_t *timep, struct tm *result) diff --git a/git-compat-util.h b/git-compat-util.h index 2bdae6725d..4ad37467e9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -351,7 +351,10 @@ struct sigaction { struct itimerval { struct timeval it_interval, it_value; }; -int git_mkdir(const char *path, int mode); +static inline int git_mkdir(const char *path, int mode) +{ + return mkdir(path); +} #define mkdir git_mkdir #include From 649a5ce8d65248df5aed42926a207f9b8f1f806a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 12:34:51 +0200 Subject: [PATCH 0012/3720] require regex (http://ftp.gnu.org/pub/gnu/regex/) --- Makefile | 2 +- compat/mingw.c | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 64d7f49019..0f3460567b 100644 --- a/Makefile +++ b/Makefile @@ -427,7 +427,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_ICONV=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS COMPAT_OBJS += compat/mingw.o - EXTLIBS += -lws2_32 + EXTLIBS += -lws2_32 -lregex X = .exe endif ifneq (,$(findstring arm,$(uname_M))) diff --git a/compat/mingw.c b/compat/mingw.c index f85b0d2f52..d2e83f74a3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -98,23 +98,6 @@ int fnmatch(const char *pattern, const char *string, int flags) return -1; } -int regcomp(regex_t *preg, const char *regex, int cflags) -{ - return -1; -} -size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) -{ - return 0; -} -void regfree(regex_t *preg) -{ -} - -int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) -{ - return -1; -} - #include struct tm *gmtime_r(const time_t *timep, struct tm *result) From b4792a360ea7acad4d45aa85ad5fdc0cf44dfbdb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 17:25:42 +0200 Subject: [PATCH 0013/3720] Include fnmatch from GNU make. --- Makefile | 4 +- compat/fnmatch.c | 488 ++++++++++++++++++++++++++++++++++++++++++++++ compat/fnmatch.h | 84 ++++++++ compat/mingw.c | 5 - git-compat-util.h | 4 +- 5 files changed, 575 insertions(+), 10 deletions(-) create mode 100755 compat/fnmatch.c create mode 100644 compat/fnmatch.h diff --git a/Makefile b/Makefile index 0f3460567b..874e529e58 100644 --- a/Makefile +++ b/Makefile @@ -425,8 +425,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease NO_ICONV=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS - COMPAT_OBJS += compat/mingw.o + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -I compat + COMPAT_OBJS += compat/mingw.o compat/fnmatch.o EXTLIBS += -lws2_32 -lregex X = .exe endif diff --git a/compat/fnmatch.c b/compat/fnmatch.c new file mode 100755 index 0000000000..1f4ead5f98 --- /dev/null +++ b/compat/fnmatch.c @@ -0,0 +1,488 @@ +/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include +#endif + +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#include +#include +#include + +#if HAVE_STRING_H || defined _LIBC +# include +#else +# include +#endif + +#if defined STDC_HEADERS || defined _LIBC +# include +#endif + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* Solaris 2.5 has a bug: must be included before . */ +# include +# include +#endif + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined _LIBC || !defined __GNU_LIBRARY__ + + +# if defined STDC_HEADERS || !defined isascii +# define ISASCII(c) 1 +# else +# define ISASCII(c) isascii(c) +# endif + +# ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +# else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +# endif +# ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +# else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +# endif + +# define ISPRINT(c) (ISASCII (c) && isprint (c)) +# define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +# define ISALNUM(c) (ISASCII (c) && isalnum (c)) +# define ISALPHA(c) (ISASCII (c) && isalpha (c)) +# define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +# define ISLOWER(c) (ISASCII (c) && islower (c)) +# define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +# define ISSPACE(c) (ISASCII (c) && isspace (c)) +# define ISUPPER(c) (ISASCII (c) && isupper (c)) +# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +# else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +# if !defined _LIBC && !defined getenv +extern char *getenv (); +# endif + +# ifndef errno +extern int errno; +# endif + +/* This function doesn't exist on most systems. */ + +# if !defined HAVE___STRCHRNUL && !defined _LIBC +static char * +__strchrnul (s, c) + const char *s; + int c; +{ + char *result = strchr (s, c); + if (result == NULL) + result = strchr (s, '\0'); + return result; +} +# endif + +# ifndef internal_function +/* Inside GNU libc we mark some function in a special way. In other + environments simply ignore the marking. */ +# define internal_function +# endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +static int internal_fnmatch __P ((const char *pattern, const char *string, + int no_leading_period, int flags)) + internal_function; +static int +internal_function +internal_fnmatch (pattern, string, no_leading_period, flags) + const char *pattern; + const char *string; + int no_leading_period; + int flags; +{ + register const char *p = pattern, *n = string; + register unsigned char c; + +/* Note that this evaluates C many times. */ +# ifdef _LIBC +# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) +# else +# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) +# endif + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if (*n == '/' && (flags & FNM_FILE_NAME)) + return FNM_NOMATCH; + else if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; + c = FOLD (c); + } + if (FOLD ((unsigned char) *n) != c) + return FNM_NOMATCH; + break; + + case '*': + if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* A slash does not match a wildcard under FNM_FILE_NAME. */ + return FNM_NOMATCH; + else if (c == '?') + { + /* A ? needs to match one character. */ + if (*n == '\0') + /* There isn't another character; no match. */ + return FNM_NOMATCH; + else + /* One character of the string is consumed in matching + this ? wildcard, so *??? won't match if there are + less than three characters. */ + ++n; + } + } + + if (c == '\0') + /* The wildcard(s) is/are the last element of the pattern. + If the name is a file name and contains another slash + this does mean it cannot match. */ + return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL + ? FNM_NOMATCH : 0); + else + { + const char *endp; + + endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0'); + + if (c == '[') + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + for (--p; n < endp; ++n) + if (internal_fnmatch (p, n, + (no_leading_period + && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))), + flags2) + == 0) + return 0; + } + else if (c == '/' && (flags & FNM_FILE_NAME)) + { + while (*n != '\0' && *n != '/') + ++n; + if (*n == '/' + && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD, + flags) == 0)) + return 0; + } + else + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + if (c == '\\' && !(flags & FNM_NOESCAPE)) + c = *p; + c = FOLD (c); + for (--p; n < endp; ++n) + if (FOLD ((unsigned char) *n) == c + && (internal_fnmatch (p, n, + (no_leading_period + && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))), + flags2) == 0)) + return 0; + } + } + + /* If we come here no match is possible with the wildcard. */ + return FNM_NOMATCH; + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + static int posixly_correct; + register int not; + char cold; + + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + + if (*n == '\0') + return FNM_NOMATCH; + + if (*n == '.' && no_leading_period && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))) + return FNM_NOMATCH; + + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* `/' cannot be matched. */ + return FNM_NOMATCH; + + not = (*p == '!' || (posixly_correct < 0 && *p == '^')); + if (not) + ++p; + + c = *p++; + for (;;) + { + unsigned char fn = FOLD ((unsigned char) *n); + + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + c = FOLD ((unsigned char) *p); + ++p; + + if (c == fn) + goto matched; + } + else if (c == '[' && *p == ':') + { + /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + size_t c1 = 0; +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) + wctype_t wt; +# endif + const char *startp = p; + + for (;;) + { + if (c1 == CHAR_CLASS_MAX_LENGTH) + /* The name is too long and therefore the pattern + is ill-formed. */ + return FNM_NOMATCH; + + c = *++p; + if (c == ':' && p[1] == ']') + { + p += 2; + break; + } + if (c < 'a' || c >= 'z') + { + /* This cannot possibly be a character class name. + Match it as a normal range. */ + p = startp; + c = '['; + goto normal_bracket; + } + str[c1++] = c; + } + str[c1] = '\0'; + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) + wt = IS_CHAR_CLASS (str); + if (wt == 0) + /* Invalid character class name. */ + return FNM_NOMATCH; + + if (__iswctype (__btowc ((unsigned char) *n), wt)) + goto matched; +# else + if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n)) + || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n)) + || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n)) + || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n)) + || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n)) + || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n)) + || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n)) + || (STREQ (str, "print") && ISPRINT ((unsigned char) *n)) + || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n)) + || (STREQ (str, "space") && ISSPACE ((unsigned char) *n)) + || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n)) + || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n))) + goto matched; +# endif + } + else if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + else + { + normal_bracket: + if (FOLD (c) == fn) + goto matched; + + cold = c; + c = *p++; + + if (c == '-' && *p != ']') + { + /* It is a range. */ + unsigned char cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + + if (cold <= fn && fn <= FOLD (cend)) + goto matched; + + c = *p++; + } + } + + if (c == ']') + break; + } + + if (!not) + return FNM_NOMATCH; + break; + + matched: + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + else if (c == '[' && *p == ':') + { + do + if (*++p == '\0') + return FNM_NOMATCH; + while (*p != ':' || p[1] == ']'); + p += 2; + c = *p; + } + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD ((unsigned char) *n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; + +# undef FOLD +} + + +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/compat/fnmatch.h b/compat/fnmatch.h new file mode 100644 index 0000000000..cc3ec37940 --- /dev/null +++ b/compat/fnmatch.h @@ -0,0 +1,84 @@ +/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _FNMATCH_H +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 +# if !defined __GLIBC__ || !defined __P +# undef __P +# define __P(protos) protos +# endif +#else /* Not C++ or ANSI C. */ +# undef __P +# define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + +#ifndef const +# if (defined __STDC__ && __STDC__) || defined __cplusplus +# define __const const +# else +# define __const +# endif +#endif + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in . */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE +# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* This value is returned if the implementation does not support + `fnmatch'. Since this is not the case here it will never be + returned but the conformance test suites still require the symbol + to be defined. */ +#ifdef _XOPEN_SOURCE +# define FNM_NOSYS (-1) +#endif + +/* Match NAME against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((__const char *__pattern, __const char *__name, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/compat/mingw.c b/compat/mingw.c index d2e83f74a3..2d3df81a8d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -93,11 +93,6 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout) return -1; } -int fnmatch(const char *pattern, const char *string, int flags) -{ - return -1; -} - #include struct tm *gmtime_r(const time_t *timep, struct tm *result) diff --git a/git-compat-util.h b/git-compat-util.h index 4ad37467e9..d361fcaee8 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -36,7 +36,7 @@ #include #include //#include -//#include +#include //#include //#include #include @@ -335,8 +335,6 @@ struct pollfd { int poll(struct pollfd *ufds, unsigned int nfds, int timeout); #define POLLIN 1 #define POLLHUP 2 -int fnmatch(const char *pattern, const char *string, int flags); -#define FNM_PATHNAME 1 typedef int siginfo_t; struct sigaction { From 27317da439ad65226cd4167163b8316627a2bbfa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 18 Sep 2006 17:15:43 +0200 Subject: [PATCH 0014/3720] implement mkstemp() --- compat/mingw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2d3df81a8d..4e44f93e21 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -77,7 +77,15 @@ const char *inet_ntop(int af, const void *src, } int mkstemp (char *__template) { - return -1; + char *temp = xstrdup(__template); + char *filename = mktemp(__template); + int fd; + + if (filename == NULL) + return -1; + fd = open(filename, O_RDWR | O_CREAT); + free(filename); + return fd; } int gettimeofday(struct timeval *tv, void *tz) { From 8d1bfddd0cd58d09da3527146f6c9eee1b244aa4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 18:48:25 +0200 Subject: [PATCH 0015/3720] make default open mode O_BINARY --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4e44f93e21..67708e5fe0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,6 +1,10 @@ #include +#include +#include #include "../git-compat-util.h" +unsigned int _CRT_fmode = _O_BINARY; + int readlink(const char *path, char *buf, size_t bufsiz) { errno = EINVAL; From 9c6663c41923c070d66b883cc26e7050f30aa387 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 18 Sep 2006 17:02:59 +0200 Subject: [PATCH 0016/3720] strip extension and handle DRIVE: notation --- Makefile | 3 ++- git.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 874e529e58..20065b7a11 100644 --- a/Makefile +++ b/Makefile @@ -425,7 +425,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease NO_ICONV=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -I compat + NO_SVN_TESTS=YesPlease + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o EXTLIBS += -lws2_32 -lregex X = .exe diff --git a/git.c b/git.c index a291177701..f893f373e1 100644 --- a/git.c +++ b/git.c @@ -280,6 +280,15 @@ static void handle_internal_command(int argc, const char **argv, char **envp) }; int i; +#ifdef STRIP_EXTENSION + i = strlen(argv[0]) - strlen(STRIP_EXTENSION); + if (i > 0 && !strcmp(argv[0] + i, STRIP_EXTENSION)) { + char *argv0 = strdup(argv[0]); + argv[0] = cmd = argv0; + argv0[i] = '\0'; + } +#endif + /* Turn "git cmd --help" into "git help cmd" */ if (argc > 1 && !strcmp(argv[1], "--help")) { argv[1] = argv[0]; @@ -325,6 +334,16 @@ int main(int argc, const char **argv, char **envp) cmd = slash; } +#ifdef __MINGW32__ + slash = strrchr(cmd, '\\'); + if (slash) { + *slash++ = 0; + if (cmd[1] == ':') + exec_path = cmd; + cmd = slash; + } +#endif + /* * "git-xxxx" is the same as "git xxxx", but we obviously: * From 4a4ae17738a52abf6dbd64ba9f01fe497229337d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 12:29:28 +0200 Subject: [PATCH 0017/3720] close fd of lockfile before unlinking --- cache.h | 1 + lockfile.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cache.h b/cache.h index e6e19bdef3..c944e843e0 100644 --- a/cache.h +++ b/cache.h @@ -180,6 +180,7 @@ extern int refresh_cache(unsigned int flags); struct lock_file { struct lock_file *next; + int fd; char on_list; char filename[PATH_MAX]; }; diff --git a/lockfile.c b/lockfile.c index 4824f4dc02..bf80246dc3 100644 --- a/lockfile.c +++ b/lockfile.c @@ -8,8 +8,10 @@ static struct lock_file *lock_file_list; static void remove_lock_file(void) { while (lock_file_list) { - if (lock_file_list->filename[0]) + if (lock_file_list->filename[0]) { + close(lock_file_list->fd); unlink(lock_file_list->filename); + } lock_file_list = lock_file_list->next; } } @@ -23,10 +25,9 @@ static void remove_lock_file_on_signal(int signo) static int lock_file(struct lock_file *lk, const char *path) { - int fd; sprintf(lk->filename, "%s.lock", path); - fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); - if (0 <= fd) { + lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); + if (0 <= lk->fd) { if (!lk->on_list) { lk->next = lock_file_list; lock_file_list = lk; @@ -42,7 +43,7 @@ static int lock_file(struct lock_file *lk, const char *path) } else lk->filename[0] = 0; - return fd; + return lk->fd; } int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error) @@ -57,9 +58,11 @@ int commit_lock_file(struct lock_file *lk) { char result_file[PATH_MAX]; int i; + close(lk->fd); strcpy(result_file, lk->filename); i = strlen(result_file) - 5; /* .lock */ result_file[i] = 0; + unlink(result_file); i = rename(lk->filename, result_file); lk->filename[0] = 0; return i; @@ -67,8 +70,10 @@ int commit_lock_file(struct lock_file *lk) void rollback_lock_file(struct lock_file *lk) { - if (lk->filename[0]) + if (lk->filename[0]) { + close(lk->fd); unlink(lk->filename); + } lk->filename[0] = 0; } From 41dfee75f14528b1978980da5bea6d8f7eb02b63 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 15:09:40 +0200 Subject: [PATCH 0018/3720] fix 'git bla' for .exe files --- exec_cmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 3996bce33f..18b9659e6e 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -44,9 +44,11 @@ int execv_git_cmd(const char **argv) const char *exec_dir = paths[i]; const char *tmp; - if (!exec_dir || !*exec_dir) continue; - +#ifdef __MINGW32__ + if (*exec_dir != '/' && exec_dir[1] != ':') { +#else if (*exec_dir != '/') { +#endif if (!getcwd(git_command, sizeof(git_command))) { fprintf(stderr, "git: cannot determine " "current directory: %s\n", From 1c68fe96bcb66ce340cb1cc40acaddaba2f7fc11 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 19:03:20 +0200 Subject: [PATCH 0019/3720] unlink target of rename before renaming --- refs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/refs.c b/refs.c index 7d858637c4..1c0bf70f2c 100644 --- a/refs.c +++ b/refs.c @@ -339,6 +339,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master) error("Unable to write to %s", lockpath); return -2; } + unlink(git_HEAD); if (rename(lockpath, git_HEAD) < 0) { unlink(lockpath); error("Unable to create %s", git_HEAD); From c9467728c6b88dd4392c70d871c629454ff55738 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 12:00:06 +0200 Subject: [PATCH 0020/3720] close fd before renaming --- config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.c b/config.c index b6082f597c..7ada9b73c5 100644 --- a/config.c +++ b/config.c @@ -812,6 +812,8 @@ int git_config_set_multivar(const char* key, const char* value, unlink(config_filename); } + close(fd); + fd = -1; if (rename(lock_file, config_filename) < 0) { fprintf(stderr, "Could not rename the lock file?\n"); ret = 4; From 4720571a2d6b27de32db3367817d71da0f9b0535 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 27 Dec 2006 15:36:36 +0100 Subject: [PATCH 0021/3720] Fix mkstemp emulation to not free the template string. The template argument was strduped unnecessarily and then not used, and the wrong string was freed. --- compat/mingw.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 67708e5fe0..ac4d4eb7fe 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -81,15 +81,10 @@ const char *inet_ntop(int af, const void *src, } int mkstemp (char *__template) { - char *temp = xstrdup(__template); char *filename = mktemp(__template); - int fd; - if (filename == NULL) return -1; - fd = open(filename, O_RDWR | O_CREAT); - free(filename); - return fd; + return open(filename, O_RDWR | O_CREAT); } int gettimeofday(struct timeval *tv, void *tz) { From 5a9f377e1db79f18c7acdede78b47ac32d6abf2b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 08:49:31 +0100 Subject: [PATCH 0022/3720] Add back the exec_path checks that were removed inadvertedly. --- exec_cmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exec_cmd.c b/exec_cmd.c index 18b9659e6e..68c39e348c 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -44,6 +44,8 @@ int execv_git_cmd(const char **argv) const char *exec_dir = paths[i]; const char *tmp; + if (!exec_dir || !*exec_dir) continue; + #ifdef __MINGW32__ if (*exec_dir != '/' && exec_dir[1] != ':') { #else From 861429a7c37cce27b07331ab9106c3c52c68cf2d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 08:54:11 +0100 Subject: [PATCH 0023/3720] Be prepared for DOS-like drive letters in the getcwd() result. An earlier patch has implemented getcwd() so that it converts the drive letter into the POSIX-like path that is used internally by MinGW (C:\foo => /c/foo), but this style does not work outside the MinGW shell. It is better to just convert the backslashes to forward slashes and handle the drive letter explicitly. --- compat/mingw.c | 2 -- setup.c | 12 ++++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ac4d4eb7fe..f22ab57461 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -122,8 +122,6 @@ char *mingw_getcwd(char *pointer, int len) return ret; if (pointer[0] != 0 && pointer[1] == ':') { int i; - pointer[1] = pointer[0]; - pointer[0] = '/'; for (i = 2; pointer[i]; i++) /* Thanks, Bill. You'll burn in hell for that. */ if (pointer[i] == '\\') diff --git a/setup.c b/setup.c index cc97f9f5c1..707f8f9a55 100644 --- a/setup.c +++ b/setup.c @@ -173,6 +173,7 @@ const char *setup_git_directory_gently(int *nongit_ok) static char cwd[PATH_MAX+1]; const char *gitdirenv; int len, offset; + int minoffset = 0; /* * If GIT_DIR is set explicitly, we're not going @@ -192,8 +193,15 @@ const char *setup_git_directory_gently(int *nongit_ok) die("Not a git repository: '%s'", gitdirenv); } +#ifdef __MINGW32__ + if (!getcwd(cwd, sizeof(cwd)) || !(cwd[0] == '/' || cwd[1] == ':')) + die("Unable to read current working directory"); + if (cwd[1] == ':') + minoffset = 2; +#else if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/') die("Unable to read current working directory"); +#endif offset = len = strlen(cwd); for (;;) { @@ -201,7 +209,7 @@ const char *setup_git_directory_gently(int *nongit_ok) break; chdir(".."); do { - if (!offset) { + if (offset <= minoffset) { if (is_git_directory(cwd)) { if (chdir(cwd)) die("Cannot come back to cwd"); @@ -216,7 +224,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } die("Not a git repository"); } - } while (cwd[--offset] != '/'); + } while (offset > minoffset && cwd[--offset] != '/'); } if (offset == len) From d9634b14f93e9611c110ef4bacf2ce46e1a23268 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 08:56:45 +0100 Subject: [PATCH 0024/3720] Windows does not support C99 format strings. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 20065b7a11..9d4944a12d 100644 --- a/Makefile +++ b/Makefile @@ -425,6 +425,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease NO_ICONV=YesPlease + NO_C99_FORMAT = YesPlease NO_SVN_TESTS=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o From 90262b5faeceac9e3c63933e6350f01a52279189 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 08:57:42 +0100 Subject: [PATCH 0025/3720] Use the Windows style PATH separator. --- git.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git.c b/git.c index f893f373e1..8b31a0fcab 100644 --- a/git.c +++ b/git.c @@ -20,7 +20,11 @@ static void prepend_to_path(const char *dir, int len) path = xmalloc(path_len + 1); memcpy(path, dir, len); +#ifdef __MINGW32__ + path[len] = ';'; +#else path[len] = ':'; +#endif memcpy(path + len + 1, old_path, path_len - len); setenv("PATH", path, 1); From 2de27f2cbb43b30d5465be33541c98b453a076e6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 09:01:17 +0100 Subject: [PATCH 0026/3720] Implement a wrapper of execve that can invoke shell scripts. When an external git command is invoked, it can be a Bourne shell script. This patch looks into the command file to see whether it is one. In this case, the command line is rearranged to invoke the shell with the proper arguments. Moreover, the arguments are quoted if necessary because Windows' spawn functions paste the arguments again into a command line that is disassembled by the invoked process. --- compat/mingw.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 2 ++ 2 files changed, 90 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index f22ab57461..18aecd9bf5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -139,3 +139,91 @@ void sync(void) void openlog(const char *ident, int option, int facility) { } + +static const char *quote_arg(const char *arg) +{ + /* count chars to quote */ + int len = 0, n = 0; + int force_quotes = 0; + char *q, *d; + const char *p = arg; + while (*p) { + if (isspace(*p)) + force_quotes = 1; + else if (*p == '"' || *p == '\\') + n++; + len++; + p++; + } + if (!force_quotes && n == 0) + return arg; + + /* insert \ where necessary */ + d = q = xmalloc(len+n+3); + *d++ = '"'; + while (*arg) { + if (*arg == '"' || *arg == '\\') + *d++ = '\\'; + *d++ = *arg++; + } + *d++ = '"'; + *d++ = 0; + return q; +} + +static void quote_argv(const char **dst, const char **src) +{ + while (*src) + *dst++ = quote_arg(*src++); + *dst = NULL; +} + +static int try_shell_exec(const char *cmd, const char **argv, const char **env) +{ + char buf[100], *p; + const char **sh_argv; + int n; + int fd = open(cmd, O_RDONLY); + if (fd < 0) + return 0; + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if (n < 5) /* at least '#!/sh' and not error */ + return 0; + + /* check whether the interpreter is sh */ + if (buf[0] != '#' || buf[1] != '!') + return 0; + buf[n] = '\0'; + p = strchr(buf, '\n'); + if (!p || + (p[-3] != '/' && p[-3] != '\\') || + p[-2] != 's' || p[-1] != 'h') + return 0; + + /* + * expand + * git-foo args... + * into + * sh git-foo args... + */ + for (n = 0; argv[n];) n++; + sh_argv = xmalloc((n+2)*sizeof(char*)); + sh_argv[0] = "sh"; + sh_argv[1] = cmd; + quote_argv(&sh_argv[2], &argv[1]); + n = spawnvpe(_P_WAIT, "sh", sh_argv, env); + if (n == -1) + return 1; /* indicate that we tried but failed */ + exit(n); +} + +void mingw_execve(const char *cmd, const char **argv, const char **env) +{ + /* check if git_command is a shell script */ + if (!try_shell_exec(cmd, argv, env)) { + int ret = spawnve(_P_WAIT, cmd, argv, env); + if (ret != -1) + exit(ret); + } +} diff --git a/git-compat-util.h b/git-compat-util.h index d361fcaee8..4b213815b7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -306,6 +306,8 @@ int syslog(int type, char *bufp, ...); #define LOG_DAEMON 4 unsigned int alarm(unsigned int seconds); #include +void mingw_execve(const char *cmd, const char **argv, const char **env); +#define execve mingw_execve int fork(); typedef int pid_t; pid_t waitpid(pid_t pid, int *status, int options); From ff61d9fc99a60a7c0320538a278d5f58680e120d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 09:03:45 +0100 Subject: [PATCH 0027/3720] Work around missing EISDIR errno values. Windows does not return EISDIR when a directory is opened as file. These instances are detected by checking explicitly whether the offending file is indeed a directory, and then the errno value is adjusted accordingly. --- refs.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/refs.c b/refs.c index 1c0bf70f2c..f48045c5c9 100644 --- a/refs.c +++ b/refs.c @@ -838,6 +838,15 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg) retry: if (log && rename(git_path("tmp-renamed-log"), git_path("logs/%s", newref))) { +#ifdef __MINGW32__ + if (errno == EEXIST) { + struct stat st; + if (stat(git_path("logs/%s", newref), &st) == 0 && S_ISDIR(st.st_mode)) + errno = EISDIR; + else + errno = EEXIST; + } +#endif if (errno==EISDIR || errno==ENOTDIR) { /* * rename(a, b) when b is an existing @@ -946,6 +955,15 @@ static int log_ref_write(struct ref_lock *lock, if (!(oflags & O_CREAT) && errno == ENOENT) return 0; +#ifdef __MINGW32__ + if ((oflags & O_CREAT) && errno == EACCES) { + struct stat st; + if (stat(lock->log_file, &st) == 0 && S_ISDIR(st.st_mode)) + errno = EISDIR; + else + errno = EACCES; + } +#endif if ((oflags & O_CREAT) && errno == EISDIR) { if (remove_empty_directories(lock->log_file)) { return error("There are still logs under '%s'", From 48f967a1615e785794a3b91cbde7df95b1b1614d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:30:15 +0100 Subject: [PATCH 0028/3720] Make a pipe() wrapper that uses Windows's _pipe(). --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 18aecd9bf5..6e0119ad5f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -92,7 +92,7 @@ int gettimeofday(struct timeval *tv, void *tz) } int pipe(int filedes[2]) { - return -1; + return _pipe(filedes, 4096, 0); } int poll(struct pollfd *ufds, unsigned int nfds, int timeout) From 0bb0ca215830c19220a2cc78ca7c5a3b16b6f1df Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:33:35 +0100 Subject: [PATCH 0029/3720] Windows cannot unlink() a file that is read-only. --- builtin-prune-packed.c | 10 ++++++++-- index-pack.c | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 977730064b..639fbed2fc 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -25,8 +25,14 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) memcpy(pathname + len, de->d_name, 38); if (opts & DRY_RUN) printf("rm -f %s\n", pathname); - else if (unlink(pathname) < 0) - error("unable to unlink %s", pathname); + else { +#ifdef __MINGW32__ + /* read-only files cannot be removed */ + chmod(pathname, 0666); +#endif + if (unlink(pathname) < 0) + error("unable to unlink %s", pathname); + } } pathname[len] = 0; rmdir(pathname); diff --git a/index-pack.c b/index-pack.c index 72e0962415..040957c016 100644 --- a/index-pack.c +++ b/index-pack.c @@ -700,6 +700,10 @@ static const char *write_index_file(const char *index_name, unsigned char *sha1) fd = mkstemp(tmpfile); index_name = xstrdup(tmpfile); } else { +#ifdef __MINGW32__ + /* read-only files cannot be removed */ + chmod(index_name, 0666); +#endif unlink(index_name); fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600); } From ee4a2fe93d663eaf2dbf0480cb27d2b8f2dbaee8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:35:42 +0100 Subject: [PATCH 0030/3720] MinGW cannot support sideband communication. --- fetch-pack.c | 2 ++ upload-pack.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/fetch-pack.c b/fetch-pack.c index 1530a94794..48670f9c62 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -564,6 +564,7 @@ static int fetch_pack(int fd[2], int nr_match, char **match) fprintf(stderr, "Server supports multi_ack\n"); multi_ack = 1; } +#ifndef __MINGW32__ if (server_supports("side-band-64k")) { if (verbose) fprintf(stderr, "Server supports side-band-64k\n"); @@ -574,6 +575,7 @@ static int fetch_pack(int fd[2], int nr_match, char **match) fprintf(stderr, "Server supports side-band\n"); use_sideband = 1; } +#endif if (!ref) { packet_flush(fd[1]); die("no matching remote head"); diff --git a/upload-pack.c b/upload-pack.c index 0ce8ceeeac..ec0f0cbfbe 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -537,10 +537,12 @@ static void receive_needs(void) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) use_ofs_delta = 1; +#ifndef __MINGW32__ if (strstr(line+45, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (strstr(line+45, "side-band")) use_sideband = DEFAULT_PACKET_MAX; +#endif /* We have sent all our refs already, and the other end * should have chosen out of them; otherwise they are From 4b5821b21b5fb83da0e5884ed5d43c658577d9a5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:39:08 +0100 Subject: [PATCH 0031/3720] Implement a subset of waitpid() in terms of Windows's _cwait(). --- compat/mingw.c | 6 ------ git-compat-util.h | 14 ++++++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6e0119ad5f..2f9e9dd61c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -46,12 +46,6 @@ int fork() { return -1; } -typedef int pid_t; -pid_t waitpid(pid_t pid, int *status, int options) -{ - errno = ECHILD; - return -1; -} int kill(pid_t pid, int sig) { diff --git a/git-compat-util.h b/git-compat-util.h index 4b213815b7..846969b408 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -310,12 +310,14 @@ void mingw_execve(const char *cmd, const char **argv, const char **env); #define execve mingw_execve int fork(); typedef int pid_t; -pid_t waitpid(pid_t pid, int *status, int options); -#define WIFEXITED(x) 0 -#define WEXITSTATUS(x) 1 -#define WIFSIGNALED(x) -1 -#define WTERMSIG(x) 0 -#define WNOHANG 0 +#define waitpid(pid, status, options) \ + ((options == 0) ? _cwait((status), (pid), 0) \ + : (errno = EINVAL, -1)) +#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ +#define WEXITSTATUS(x) ((x) & 0xff) +#define WIFSIGNALED(x) ((unsigned)(x) > 259) +#define WTERMSIG(x) (x) +#define WNOHANG 1 #define SIGKILL 0 #define SIGCHLD 0 #define SIGALRM 0 From aa0dba94438d061850e3a8a99f588e5b782afeda Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:45:20 +0100 Subject: [PATCH 0032/3720] Add a cpio emulation script based on GNU tar. --- Makefile | 3 ++- cpio.sh | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 cpio.sh diff --git a/Makefile b/Makefile index 9d4944a12d..2aa3bed4e6 100644 --- a/Makefile +++ b/Makefile @@ -177,7 +177,8 @@ SCRIPT_SH = \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ git-merge-resolve.sh git-merge-ours.sh \ - git-lost-found.sh git-quiltimport.sh + git-lost-found.sh git-quiltimport.sh \ + cpio.sh SCRIPT_PERL = \ git-add--interactive.perl \ diff --git a/cpio.sh b/cpio.sh new file mode 100644 index 0000000000..a0a5a372f2 --- /dev/null +++ b/cpio.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# +# Emulates some cpio behavior using GNU tar + +die() { + echo >&2 "$@" + exit 1 +} + +tr0=cat + +while test $# -gt 0; do + case "$1" in + -0) tr0="tr '\0' ' '";; + -o) mode=o;; + -iuv) ;; + -pumd|-pumdl) + mode=p + dir="$2" + shift + ;; + *) die "cpio emulation supports only -0, -o, -iuv, -pumdl";; + esac + shift +done + +case $mode in +o) + files=.cpiofiles$$ + $tr0 > $files + tar --create --file=- --files-from=$files --exclude=$files + rc=$? + rm -f $files + exit $rc + ;; +p) + files=.cpiofiles$$ + $tr0 > $files + tar --create --file=- --files-from=$files --exclude=$files | + tar --extract --directory="$dir" --file=- + rm -f $files + ;; +*) + tar xvf - || exit +esac From 0400c502c3dff7810175e364ab9422552a83ec19 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:52:29 +0100 Subject: [PATCH 0033/3720] Factor fork()/exec() work into a spawn() like function. Windows does not have fork(), but something called spawn() that is roughly equivalent to a fork()/exec() pair, factor out the Unix style code into a function that does it more similarly to spawn(). Now the Windows style spawn() can more easily be employed to achieve the same that the Unix style code does. --- Makefile | 3 +- compat/mingw.c | 2 +- connect.c | 85 +++++++++++------------------ spawn-pipe.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++ spawn-pipe.h | 4 ++ 5 files changed, 178 insertions(+), 57 deletions(-) create mode 100644 spawn-pipe.c create mode 100644 spawn-pipe.h diff --git a/Makefile b/Makefile index 2aa3bed4e6..105e2d1b6e 100644 --- a/Makefile +++ b/Makefile @@ -240,7 +240,7 @@ LIB_H = \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ - utf8.h + spawn-pipe.h utf8.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ @@ -252,6 +252,7 @@ LIB_OBJS = \ date.o diff-delta.o entry.o exec_cmd.o ident.o \ interpolate.o \ lockfile.o \ + spawn-pipe.o \ object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \ reachable.o \ quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \ diff --git a/compat/mingw.c b/compat/mingw.c index 2f9e9dd61c..8b8282bfd5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -165,7 +165,7 @@ static const char *quote_arg(const char *arg) return q; } -static void quote_argv(const char **dst, const char **src) +void quote_argv(const char **dst, const char **src) { while (*src) *dst++ = quote_arg(*src++); diff --git a/connect.c b/connect.c index 66daa11a57..171f34837f 100644 --- a/connect.c +++ b/connect.c @@ -3,6 +3,7 @@ #include "pkt-line.h" #include "quote.h" #include "refs.h" +#include "spawn-pipe.h" static char *server_capabilities; @@ -620,23 +621,13 @@ static void git_proxy_connect(int fd[2], char *host) if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0) die("unable to create pipe pair for communication"); - pid = fork(); - if (!pid) { - dup2(pipefd[1][0], 0); - dup2(pipefd[0][1], 1); - close(pipefd[0][0]); - close(pipefd[0][1]); - close(pipefd[1][0]); - close(pipefd[1][1]); - execlp(git_proxy_command, git_proxy_command, host, port, NULL); - die("exec failed"); + + { + const char *argv[] = { NULL, host, port, NULL }; + spawnvpe_pipe(git_proxy_command, argv, environ, pipefd[1], pipefd[0]); } - if (pid < 0) - die("fork failed"); fd[0] = pipefd[0][0]; fd[1] = pipefd[1][1]; - close(pipefd[0][1]); - close(pipefd[1][0]); } #define MAX_CMD_LEN 1024 @@ -740,53 +731,37 @@ pid_t git_connect(int fd[2], char *url, const char *prog) if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0) die("unable to create pipe pair for communication"); - pid = fork(); - if (pid < 0) - die("unable to fork"); - if (!pid) { - char command[MAX_CMD_LEN]; - char *posn = command; - int size = MAX_CMD_LEN; - int of = 0; - of |= add_to_string(&posn, &size, prog, 0); - of |= add_to_string(&posn, &size, " ", 0); - of |= add_to_string(&posn, &size, path, 1); + char command[MAX_CMD_LEN]; + char *posn = command; + int size = MAX_CMD_LEN; + int of = 0; - if (of) - die("command line too long"); + of |= add_to_string(&posn, &size, prog, 0); + of |= add_to_string(&posn, &size, " ", 0); + of |= add_to_string(&posn, &size, path, 1); - dup2(pipefd[1][0], 0); - dup2(pipefd[0][1], 1); - close(pipefd[0][0]); - close(pipefd[0][1]); - close(pipefd[1][0]); - close(pipefd[1][1]); - if (protocol == PROTO_SSH) { - const char *ssh, *ssh_basename; - ssh = getenv("GIT_SSH"); - if (!ssh) ssh = "ssh"; - ssh_basename = strrchr(ssh, '/'); - if (!ssh_basename) - ssh_basename = ssh; - else - ssh_basename++; - execlp(ssh, ssh_basename, host, command, NULL); - } - else { - unsetenv(ALTERNATE_DB_ENVIRONMENT); - unsetenv(DB_ENVIRONMENT); - unsetenv(GIT_DIR_ENVIRONMENT); - unsetenv(GRAFT_ENVIRONMENT); - unsetenv(INDEX_ENVIRONMENT); - execlp("sh", "sh", "-c", command, NULL); - } - die("exec failed"); + if (of) + die("command line too long"); + + if (protocol == PROTO_SSH) { + const char *argv[] = { NULL, host, command, NULL }; + const char *ssh = getenv("GIT_SSH"); + if (!ssh) ssh = "ssh"; + pid = spawnvpe_pipe(ssh, argv, environ, pipefd[1], pipefd[0]); + } + else { + const char *argv[] = { NULL, "-c", command, NULL }; + const char **env = copy_environ(); + env_unsetenv(env, ALTERNATE_DB_ENVIRONMENT); + env_unsetenv(env, DB_ENVIRONMENT); + env_unsetenv(env, GIT_DIR_ENVIRONMENT); + env_unsetenv(env, GRAFT_ENVIRONMENT); + env_unsetenv(env, INDEX_ENVIRONMENT); + pid = spawnvpe_pipe("sh", argv, env, pipefd[1], pipefd[0]); } fd[0] = pipefd[0][0]; fd[1] = pipefd[1][1]; - close(pipefd[0][1]); - close(pipefd[1][0]); if (free_path) free(path); return pid; diff --git a/spawn-pipe.c b/spawn-pipe.c new file mode 100644 index 0000000000..fc179c8cdc --- /dev/null +++ b/spawn-pipe.c @@ -0,0 +1,141 @@ +#include "git-compat-util.h" +#include "spawn-pipe.h" + +extern char **environ; + +/* cmd specifies the command to invoke. + * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. + * env specifies the environment. + * pin and pout specify pipes; the read end of pin is made the standard input + * of the spawned process, and the write end of pout is mad the standard output. + * The respective unused ends of the pipes are closed both in the parent + * process as well as in the child process. + * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to + * indicate that no processing shall occur. + */ +int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, + int pin[], int pout[]) +{ + const char *cmd_basename = strrchr(cmd, '/'); + pid_t pid; + +#ifdef __MINGW32__ + int s0 = -1, s1 = -1, argc; + const char **qargv; + extern void quote_argv(const char **dst, const char **src); + + if (!cmd_basename) + cmd_basename = strrchr(cmd, '\\'); +#endif + + if (!cmd_basename) + cmd_basename = cmd; + else + cmd_basename++; + argv[0] = cmd_basename; + +#ifndef __MINGW32__ + pid = fork(); + if (pid < 0) + die("unable to fork"); + if (!pid) { + if (pin) { + if (pin[0] >= 0) { + dup2(pin[0], 0); + close(pin[0]); + } + if (pin[1] >= 0) + close(pin[1]); + } + if (pout) { + if (pout[1] >= 0) { + dup2(pout[1], 1); + close(pout[1]); + } + if (pout[0] >= 0) + close(pout[0]); + } + environ = env; + execvp(cmd, argv); + die("exec failed"); + } + + if (pin && pin[0] >= 0) + close(pin[0]); + if (pout && pout[1] >= 1) + close(pout[1]); +#else + if (pin) { + if (pin[0] >= 0) { + s0 = dup(0); + dup2(pin[0], 0); + close(pin[0]); + } + } + if (pout) { + if (pout[1] >= 0) { + s1 = dup(1); + dup2(pout[1], 1); + close(pout[1]); + } + } + + for (argc = 0; argv[argc];) argc++; + qargv = xmalloc((argc+2)*sizeof(char*)); + quote_argv(qargv, argv); + + pid = spawnvpe(_P_NOWAIT, cmd, qargv, env); + + free(qargv); /* TODO: quoted args should be freed, too */ + + if (s0 >= 0) { + dup2(s0, 0); + close(s0); + } + if (s1 >= 0) { + dup2(s1, 1); + close(s1); + } +#endif + + return pid; +} + +const char **copy_environ() +{ + return copy_env(environ); +} + +const char **copy_env(const char **env) +{ + const char **s; + int n = 1; + for (s = env; *s; s++) + n++; + s = xmalloc(n*sizeof(const char *)); + memcpy(s, env, n*sizeof(const char *)); + return s; +} + +void env_unsetenv(const char **env, const char *name) +{ + int src, dst; + size_t nmln; + + nmln = strlen(name); + + for (src = dst = 0; env[src]; ++src) { + size_t enln; + enln = strlen(env[src]); + if (enln > nmln) { + /* might match, and can test for '=' safely */ + if (0 == strncmp (env[src], name, nmln) + && '=' == env[src][nmln]) + /* matches, so skip */ + continue; + } + env[dst] = env[src]; + ++dst; + } + env[dst] = NULL; +} diff --git a/spawn-pipe.h b/spawn-pipe.h new file mode 100644 index 0000000000..41eb81de63 --- /dev/null +++ b/spawn-pipe.h @@ -0,0 +1,4 @@ +int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); +const char **copy_environ(); +const char **copy_env(const char **env); +void env_unsetenv(const char **env, const char *name); From 8f9e40a3964d003f04e56520ad7b18a1abda13c6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 17:49:34 +0100 Subject: [PATCH 0034/3720] Use the spawn workhorse instead of a fork()/exec() pair. --- diff.c | 13 +++---------- merge-index.c | 20 +++----------------- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/diff.c b/diff.c index f11a633da5..12161b6f87 100644 --- a/diff.c +++ b/diff.c @@ -8,6 +8,7 @@ #include "delta.h" #include "xdiff-interface.h" #include "color.h" +#include "spawn-pipe.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -1498,13 +1499,7 @@ static int spawn_prog(const char *pgm, const char **arg) int status; fflush(NULL); - pid = fork(); - if (pid < 0) - die("unable to fork"); - if (!pid) { - execvp(pgm, (char *const*) arg); - exit(255); - } + pid = spawnvpe_pipe(pgm, arg, environ, NULL, NULL); while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) @@ -1545,7 +1540,7 @@ static void run_external_diff(const char *pgm, int retval; static int atexit_asked = 0; const char *othername; - const char **arg = &spawn_arg[0]; + const char **arg = &spawn_arg[1]; othername = (other? other : name); if (one && two) { @@ -1561,7 +1556,6 @@ static void run_external_diff(const char *pgm, } if (one && two) { - *arg++ = pgm; *arg++ = name; *arg++ = temp[0].name; *arg++ = temp[0].hex; @@ -1574,7 +1568,6 @@ static void run_external_diff(const char *pgm, *arg++ = xfrm_msg; } } else { - *arg++ = pgm; *arg++ = name; } *arg = NULL; diff --git a/merge-index.c b/merge-index.c index a9983dd78a..6c2e00842e 100644 --- a/merge-index.c +++ b/merge-index.c @@ -1,29 +1,16 @@ #include "cache.h" +#include "spawn-pipe.h" static const char *pgm; -static const char *arguments[8]; +static const char *arguments[9]; /* last one is always NULL */ static int one_shot, quiet; static int err; static void run_program(void) { - pid_t pid = fork(); + pid_t pid = spawnvpe_pipe(pgm, arguments, environ, NULL, NULL); int status; - if (pid < 0) - die("unable to fork"); - if (!pid) { - execlp(pgm, arguments[0], - arguments[1], - arguments[2], - arguments[3], - arguments[4], - arguments[5], - arguments[6], - arguments[7], - NULL); - die("unable to execute '%s'", pgm); - } if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) { if (one_shot) { err++; @@ -41,7 +28,6 @@ static int merge_entry(int pos, const char *path) if (pos >= active_nr) die("git-merge-index: %s not in the cache", path); - arguments[0] = pgm; arguments[1] = ""; arguments[2] = ""; arguments[3] = ""; From e7a70c5ddfa0f925760c131c2c60c25b814df222 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 17:46:07 +0100 Subject: [PATCH 0035/3720] Windows does not have the close-on-exec flag. --- sha1_file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sha1_file.c b/sha1_file.c index 3025440941..14ec604797 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -572,6 +572,7 @@ static void open_packed_git(struct packed_git *p) } else if (p->pack_size != st.st_size) die("packfile %s size changed", p->pack_name); +#ifndef __MINGW32__ /* We leave these file descriptors open with sliding mmap; * there is no point keeping them open across exec(), though. */ @@ -581,6 +582,7 @@ static void open_packed_git(struct packed_git *p) fd_flag |= FD_CLOEXEC; if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1) die("cannot set FD_CLOEXEC"); +#endif /* Verify we recognize this pack file format. */ if (read_in_full(p->pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) From 2bd27c7c97f73a8da1c65a2d0096e094283ac59f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 17:48:23 +0100 Subject: [PATCH 0036/3720] Report failure when a process cannot be spawned (MinGW only). --- spawn-pipe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spawn-pipe.c b/spawn-pipe.c index fc179c8cdc..716c52902c 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -85,6 +85,8 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, quote_argv(qargv, argv); pid = spawnvpe(_P_NOWAIT, cmd, qargv, env); + if (pid < 0) + die("unable to run %s", cmd); free(qargv); /* TODO: quoted args should be freed, too */ From 4ba0bd54b35f6ac637ec1274911dde1629aa04a1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 17:45:25 +0100 Subject: [PATCH 0037/3720] rename() fails on Windows if the destination exists. --- builtin-reflog.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/builtin-reflog.c b/builtin-reflog.c index 6d14184736..4877bb060b 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -274,6 +274,12 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, if (fclose(cb.newlog)) status |= error("%s: %s", strerror(errno), newlog_path); +#ifdef __MINGW32__ + /* rename fails if the destination exists */ + if (unlink(lock->log_file)) + status |= error("cannot remove %s", lock->log_file); + else +#endif if (rename(newlog_path, lock->log_file)) { status |= error("cannot rename %s to %s", newlog_path, lock->log_file); From 09653a29cf4e6c010997c5a7da7945573da34612 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 11 Jan 2007 13:45:41 +0100 Subject: [PATCH 0038/3720] Move script detection into a helper function that returns the interpreter. This will be needed later in the spawn helper functions, too, where we want to start a shell or perl script from an exe. --- compat/mingw.c | 45 +++++++++++++++++++++++++++++++-------------- git-compat-util.h | 3 +++ spawn-pipe.c | 1 - 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8b8282bfd5..53b3f780a4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -172,27 +172,44 @@ void quote_argv(const char **dst, const char **src) *dst = NULL; } -static int try_shell_exec(const char *cmd, const char **argv, const char **env) +const char *parse_interpreter(const char *cmd) { - char buf[100], *p; - const char **sh_argv; - int n; - int fd = open(cmd, O_RDONLY); + static char buf[100]; + char *p; + int n, fd; + + /* don't even try a .exe */ + n = strlen(cmd); + if (n >= 4 && !strcasecmp(cmd+n-4, ".exe")) + return NULL; + + fd = open(cmd, O_RDONLY); if (fd < 0) - return 0; + return NULL; n = read(fd, buf, sizeof(buf)-1); close(fd); - if (n < 5) /* at least '#!/sh' and not error */ - return 0; + if (n < 4) /* at least '#!/x' and not error */ + return NULL; - /* check whether the interpreter is sh */ if (buf[0] != '#' || buf[1] != '!') - return 0; + return NULL; buf[n] = '\0'; p = strchr(buf, '\n'); - if (!p || - (p[-3] != '/' && p[-3] != '\\') || - p[-2] != 's' || p[-1] != 'h') + if (!p) + return NULL; + + *p = '\0'; + if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\'))) + return NULL; + return p+1; +} + +static int try_shell_exec(const char *cmd, const char **argv, const char **env) +{ + const char **sh_argv; + int n; + const char *interpr = parse_interpreter(cmd); + if (!interpr) return 0; /* @@ -203,7 +220,7 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) */ for (n = 0; argv[n];) n++; sh_argv = xmalloc((n+2)*sizeof(char*)); - sh_argv[0] = "sh"; + sh_argv[0] = interpr; sh_argv[1] = cmd; quote_argv(&sh_argv[2], &argv[1]); n = spawnvpe(_P_WAIT, "sh", sh_argv, env); diff --git a/git-compat-util.h b/git-compat-util.h index 846969b408..bf42191ab7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -370,4 +370,7 @@ char *mingw_getcwd(char *pointer, int len); #define setlinebuf(x) #define fsync(x) +extern void quote_argv(const char **dst, const char **src); +extern const char *parse_interpreter(const char *cmd); + #endif diff --git a/spawn-pipe.c b/spawn-pipe.c index 716c52902c..87ad789775 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -22,7 +22,6 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, #ifdef __MINGW32__ int s0 = -1, s1 = -1, argc; const char **qargv; - extern void quote_argv(const char **dst, const char **src); if (!cmd_basename) cmd_basename = strrchr(cmd, '\\'); From 23960ed3c315dc0f39cebcf317ff4d3ba16ccee8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 12 Jan 2007 10:10:25 +0100 Subject: [PATCH 0039/3720] Enable the spawn workhorse function to spawn shell scripts. For this purpose the path lookup is done manually, and the found file is inspected for the interpreter. If one is found, the script is spawned under the interpreter; otherwise, the program is spawned normally. --- spawn-pipe.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/spawn-pipe.c b/spawn-pipe.c index 87ad789775..53a1487d32 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -3,6 +3,53 @@ extern char **environ; +#ifdef __MINGW32__ +static char *lookup_prog(const char *dir, const char *cmd, int tryexe) +{ + char path[MAX_PATH]; + snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); + + if (tryexe && access(path, 0) == 0) + return xstrdup(path); + path[strlen(path)-4] = '\0'; + if (access(path, 0) == 0) + return xstrdup(path); + return NULL; +} + +/* + * Determines the absolute path of cmd based on the PATH environment variable. + * If cmd contains a slash or backslash, no lookup is performed. + */ +static char *path_lookup(const char *cmd) +{ + char *p, *envpath = getenv("PATH"); + char *prog = NULL; + int len = strlen(cmd); + int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); + + if (strchr(cmd, '/') || strchr(cmd, '\\') || + !envpath || !*envpath) + envpath = ""; + envpath = xstrdup(envpath); + p = envpath; + while (p && !prog) { + const char *dir = p; + p = strchr(p, ';'); + if (p) *p++ = '\0'; + if (*dir) + prog = lookup_prog(dir, cmd, tryexe); + } + free(envpath); + if (!prog) { + prog = lookup_prog(".", cmd, tryexe); + if (!prog) + prog = xstrdup(cmd); + } + return prog; +} +#endif + /* cmd specifies the command to invoke. * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. * env specifies the environment. @@ -21,7 +68,8 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, #ifdef __MINGW32__ int s0 = -1, s1 = -1, argc; - const char **qargv; + char *prog; + const char **qargv, *interpr; if (!cmd_basename) cmd_basename = strrchr(cmd, '\\'); @@ -79,15 +127,26 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, } } + prog = path_lookup(cmd); + interpr = parse_interpreter(prog); + for (argc = 0; argv[argc];) argc++; qargv = xmalloc((argc+2)*sizeof(char*)); - quote_argv(qargv, argv); + if (!interpr) { + quote_argv(qargv, argv); + pid = spawnve(_P_NOWAIT, prog, qargv, env); + } else { + qargv[0] = interpr; + argv[0] = prog; + quote_argv(&qargv[1], argv); + pid = spawnvpe(_P_NOWAIT, interpr, qargv, env); + } - pid = spawnvpe(_P_NOWAIT, cmd, qargv, env); if (pid < 0) die("unable to run %s", cmd); free(qargv); /* TODO: quoted args should be freed, too */ + free(prog); if (s0 >= 0) { dup2(s0, 0); From 5f38ff014e868ea0ae9210b4a2fbd56ebc8283da Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 16 Jan 2007 14:58:49 +0100 Subject: [PATCH 0040/3720] Split PATH into parts in advance, and pass the result to the new spawnvppe_pipe. --- spawn-pipe.c | 88 ++++++++++++++++++++++++++++++++++++++++++---------- spawn-pipe.h | 1 + 2 files changed, 73 insertions(+), 16 deletions(-) diff --git a/spawn-pipe.c b/spawn-pipe.c index 53a1487d32..b828809820 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -18,29 +18,72 @@ static char *lookup_prog(const char *dir, const char *cmd, int tryexe) } /* - * Determines the absolute path of cmd based on the PATH environment variable. + * Splits the PATH into parts. + */ +char **get_path_split() +{ + char *p, **path, *envpath = getenv("PATH"); + int i, n = 0; + + if (!envpath || !*envpath) + return NULL; + + envpath = xstrdup(envpath); + p = envpath; + while (p) { + char *dir = p; + p = strchr(p, ';'); + if (p) *p++ = '\0'; + if (*dir) { /* not earlier, catches series of ; */ + ++n; + } + } + if (!n) + return NULL; + + path = xmalloc((n+1)*sizeof(char*)); + p = envpath; + i = 0; + do { + if (*p) + path[i++] = xstrdup(p); + p = p+strlen(p)+1; + } while (i < n); + path[i] = NULL; + + free(envpath); + + return path; +} + +void free_path_split(char **path) +{ + if (!path) + return; + + char **p = path; + while (*p) + free(*p++); + free(path); +} + +/* + * Determines the absolute path of cmd using the the split path in path. * If cmd contains a slash or backslash, no lookup is performed. */ -static char *path_lookup(const char *cmd) +static char *path_lookup(const char *cmd, char **path) { - char *p, *envpath = getenv("PATH"); + char **p = path; char *prog = NULL; int len = strlen(cmd); int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); - if (strchr(cmd, '/') || strchr(cmd, '\\') || - !envpath || !*envpath) - envpath = ""; - envpath = xstrdup(envpath); - p = envpath; - while (p && !prog) { - const char *dir = p; - p = strchr(p, ';'); - if (p) *p++ = '\0'; - if (*dir) - prog = lookup_prog(dir, cmd, tryexe); + if (strchr(cmd, '/') || strchr(cmd, '\\')) + p = NULL; + + while (*p && !prog) { + prog = lookup_prog(*p++, cmd, tryexe); } - free(envpath); if (!prog) { prog = lookup_prog(".", cmd, tryexe); if (!prog) @@ -62,6 +105,19 @@ static char *path_lookup(const char *cmd) */ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]) +{ + char **path = get_path_split(); + + pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); + + free_path_split(path); + + return pid; +} + +int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, + char **path, + int pin[], int pout[]) { const char *cmd_basename = strrchr(cmd, '/'); pid_t pid; @@ -127,7 +183,7 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, } } - prog = path_lookup(cmd); + prog = path_lookup(cmd, path); interpr = parse_interpreter(prog); for (argc = 0; argv[argc];) argc++; diff --git a/spawn-pipe.h b/spawn-pipe.h index 41eb81de63..3807819ae8 100644 --- a/spawn-pipe.h +++ b/spawn-pipe.h @@ -1,3 +1,4 @@ +int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); const char **copy_environ(); const char **copy_env(const char **env); From ec1fcbb0a9432e0baccc43484caa57c7c2042118 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 09:37:38 +0100 Subject: [PATCH 0041/3720] Make the pager work. --- pager.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pager.c b/pager.c index 4587fbbdb5..b2a37e2658 100644 --- a/pager.c +++ b/pager.c @@ -1,19 +1,26 @@ #include "cache.h" +#include "spawn-pipe.h" /* * This is split up from the rest of git so that we might do * something different on Windows, for example. */ +#ifndef __MINGW32__ static void run_pager(const char *pager) { execlp(pager, pager, NULL); execl("/bin/sh", "sh", "-c", pager, NULL); } +#endif void setup_pager(void) { +#ifndef __MINGW32__ pid_t pid; +#else + const char *pager_argv[] = { "sh", "-c", NULL, NULL }; +#endif int fd[2]; const char *pager = getenv("GIT_PAGER"); @@ -30,6 +37,7 @@ void setup_pager(void) if (pipe(fd) < 0) return; +#ifndef __MINGW32__ pid = fork(); if (pid < 0) { close(fd[0]); @@ -54,4 +62,14 @@ void setup_pager(void) run_pager(pager); die("unable to execute pager '%s'", pager); exit(255); +#else + /* spawn the pager */ + pager_argv[2] = pager; + if (spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL) < 0) + return; + + /* original process continues, but writes to the pipe */ + dup2(fd[1], 1); + close(fd[1]); +#endif } From 85e94b981ef0df32c3e5170499298369513bf864 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 14:04:06 +0100 Subject: [PATCH 0042/3720] Do not leak pipe file handles into the child processes. Windows's _pipe() by default allocates inheritable pipes. However, when a spawn happens, we do not have a possiblility to close the unused pipe ends in the child process. This is a problem. Consider the following situation: The child process only reads from the pipe and the parent process uses only the writable end; the parent even closes the writable end. As it happens, the child at this time usually still waits for input in a read(). But since the child has inherited an open writable end, it does not get EOF and hangs ad infinitum. For this reason, pipe handles must not be inheritable. At the first glance, this is curious, since after all it is the purpose of pipes to be inherited by child processes. However, in all cases where this inheritance is needed for a file descriptor, it is dup2()'d to stdin or stdout anyway, and, lo and behold, Windows's dup2() creates inheritable duplicates. --- compat/mingw.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 53b3f780a4..8ed621d004 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -86,7 +86,47 @@ int gettimeofday(struct timeval *tv, void *tz) } int pipe(int filedes[2]) { - return _pipe(filedes, 4096, 0); + int fd; + HANDLE h[2], parent; + + if (_pipe(filedes, 4096, 0) < 0) + return -1; + + parent = GetCurrentProcess(); + + if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[0]), + parent, &h[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) { + close(filedes[0]); + close(filedes[1]); + return -1; + } + if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[1]), + parent, &h[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) { + close(filedes[0]); + close(filedes[1]); + CloseHandle(h[0]); + return -1; + } + fd = _open_osfhandle(h[0], O_NOINHERIT); + if (fd < 0) { + close(filedes[0]); + close(filedes[1]); + CloseHandle(h[0]); + CloseHandle(h[1]); + return -1; + } + close(filedes[0]); + filedes[0] = fd; + fd = _open_osfhandle(h[1], O_NOINHERIT); + if (fd < 0) { + close(filedes[0]); + close(filedes[1]); + CloseHandle(h[1]); + return -1; + } + close(filedes[1]); + filedes[1] = fd; + return 0; } int poll(struct pollfd *ufds, unsigned int nfds, int timeout) From 16ea9c7aa337b1acb7c1041b4730a4b168096706 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 14:18:11 +0100 Subject: [PATCH 0043/3720] Make sure that the pager terminates before the process that feeds it. Since the pager was spawned as child process, it does not notice when the parent (which feeds its stdin) terminates. If the pager is 'less' it so looses control over the terminal and cannot be controled by the user anymore. For this reason, we register a function atexit() that explicitly waits for the pager to terminate. --- pager.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pager.c b/pager.c index b2a37e2658..d72c5e8d94 100644 --- a/pager.c +++ b/pager.c @@ -12,6 +12,13 @@ static void run_pager(const char *pager) execlp(pager, pager, NULL); execl("/bin/sh", "sh", "-c", pager, NULL); } +#else +static pid_t pager_pid; +static void collect_pager(void) +{ + close(1); /* signals EOF to pager */ + cwait(NULL, pager_pid, 0); +} #endif void setup_pager(void) @@ -65,11 +72,15 @@ void setup_pager(void) #else /* spawn the pager */ pager_argv[2] = pager; - if (spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL) < 0) + pager_pid = spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL); + if (pager_pid < 0) return; /* original process continues, but writes to the pipe */ dup2(fd[1], 1); close(fd[1]); + + /* this makes sure that the parent terminates after the pager */ + atexit(collect_pager); #endif } From c823cea00ef2b5e14457efe437db3a4aefe75667 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 14:04:41 +0100 Subject: [PATCH 0044/3720] Implement sleep(). --- compat/mingw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/compat/mingw.c b/compat/mingw.c index 8ed621d004..6d067c9450 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -66,6 +66,7 @@ int setitimer(int __which, const struct itimerval *__value, } unsigned int sleep (unsigned int __seconds) { + Sleep(__seconds*1000); return 0; } const char *inet_ntop(int af, const void *src, From c84f02153b70b80a7463c3bea255e773d8f5cb8f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 18:07:44 +0100 Subject: [PATCH 0045/3720] Add a spawnv_git_cmd() function and use it in fetch-pack.c. This function is intended to be used in place of exec[vl]_git_cmd() that follows a fork. It constructs the (at most) 3 paths that execv_git_cmd() searches manually for the git command and hands them over to spawnvppe_pipe(). The use case in get_pack() is one of the simplest possible. --- exec_cmd.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ exec_cmd.h | 1 + fetch-pack.c | 10 +------ 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 68c39e348c..9f31b040de 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,6 +1,7 @@ #include "cache.h" #include "exec_cmd.h" #include "quote.h" +#include "spawn-pipe.h" #define MAX_ARGS 32 extern char **environ; @@ -137,3 +138,86 @@ int execl_git_cmd(const char *cmd,...) argv[argc] = NULL; return execv_git_cmd(argv); } + +int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) +{ + char cmd[100]; + int i, rc; + pid_t pid; + const char *paths[] = { current_exec_path, + getenv(EXEC_PATH_ENVIRONMENT), + builtin_exec_path }; + char p[3][PATH_MAX + 1]; + char *usedpaths[4], **up = usedpaths; + const char *tmp; + + for (i = 0; i < ARRAY_SIZE(paths); ++i) { + size_t len; + const char *exec_dir = paths[i]; + + if (!exec_dir || !*exec_dir) continue; + +#ifdef __MINGW32__ + if (*exec_dir != '/' && exec_dir[1] != ':') { +#else + if (*exec_dir != '/') { +#endif + if (!getcwd(p[i], sizeof(p[i]))) { + fprintf(stderr, "git: cannot determine " + "current directory: %s\n", + strerror(errno)); + return -1; + } + len = strlen(p[i]); + + /* Trivial cleanup */ + while (!strncmp(exec_dir, "./", 2)) { + exec_dir += 2; + while (*exec_dir == '/') + exec_dir++; + } + + rc = snprintf(p[i] + len, + sizeof(p[i]) - len, "/%s", + exec_dir); + if (rc < 0 || rc >= sizeof(p[i]) - len) { + fprintf(stderr, "git: command name given " + "is too long.\n"); + return -1; + } + } else { + if (strlen(exec_dir) + 1 > sizeof(p[i])) { + fprintf(stderr, "git: command name given " + "is too long.\n"); + return -1; + } + strcpy(p[i], exec_dir); + } + *up++ = p[i]; + } + *up = NULL; + + rc = snprintf(cmd, sizeof(cmd), "git-%s", argv[0]); + if (rc < 0 || rc >= sizeof(cmd)) { + fprintf(stderr, + "git: command name given is too long.\n"); + return -1; + } + + /* argv[0] must be the git command, but the argv array + * belongs to the caller. Save argv[0] and + * restore it later. + */ + + tmp = argv[0]; + argv[0] = cmd; + + trace_argv_printf(argv, -1, "trace: exec:"); + + pid = spawnvppe_pipe(cmd, argv, environ, usedpaths, + pin, pout); + + argv[0] = tmp; + return pid; + +} diff --git a/exec_cmd.h b/exec_cmd.h index 989621ff4e..eefb4afe40 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -5,6 +5,7 @@ extern void git_set_exec_path(const char *exec_path); extern const char* git_exec_path(void); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); +extern int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]); #endif /* __GIT_EXEC_CMD_H_ */ diff --git a/fetch-pack.c b/fetch-pack.c index 48670f9c62..10683bee9a 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -493,17 +493,9 @@ static int get_pack(int xd[2], const char **argv) int fd[2]; side_pid = setup_sideband(fd, xd); - pid = fork(); + pid = spawnv_git_cmd(argv, fd, NULL); if (pid < 0) die("fetch-pack: unable to fork off %s", argv[0]); - if (!pid) { - dup2(fd[0], 0); - close(fd[0]); - close(fd[1]); - execv_git_cmd(argv); - die("%s exec failed", argv[0]); - } - close(fd[0]); close(fd[1]); while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) From 2d6dacec88dd8dddae75b4a60b7a1944ac278354 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 19 Jan 2007 13:03:09 +0100 Subject: [PATCH 0046/3720] Make upload-pack.c work under MinGW. The forked rev-list process is turned into a thread. This should be OK since the rest of upload-pack does not access the revision machinery. In order to avoid the poll() call that waits for two file descriptors, it was necessary to remove sideband support. Then only one file descriptor needs to be monitored, which can be done in a simple while loop. --- upload-pack.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/upload-pack.c b/upload-pack.c index ec0f0cbfbe..ace719ce1a 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -96,7 +96,7 @@ static void show_edge(struct commit *commit) fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1)); } -static void do_rev_list(int create_full_pack) +static void do_rev_list(void *create_full_pack) { int i; struct rev_info revs; @@ -130,10 +130,13 @@ static void do_rev_list(int create_full_pack) prepare_revision_walk(&revs); mark_edges_uninteresting(revs.commits, &revs, show_edge); traverse_commit_list(&revs, show_commit, show_object); + fflush(pack_pipe); + fclose(pack_pipe); } static void create_pack_file(void) { +#ifndef __MINGW32__ /* Pipes between rev-list to pack-objects, pack-objects to us * and pack-objects error stream for progress bar. */ @@ -339,6 +342,86 @@ static void create_pack_file(void) kill(pid_rev_list, SIGKILL); send_client_data(3, abort_msg, sizeof(abort_msg)); die("git-upload-pack: %s", abort_msg); +#else + /* Pipes between rev-list to pack-objects, pack-objects to us. */ + int lp_pipe[2], pu_pipe[2]; + pid_t pid_pack_objects; + int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); + char data[8193]; + char abort_msg[] = "aborting due to possible repository " + "corruption on the remote side."; + int buffered = -1; + ssize_t sz; + char *cp; + const char* argv[] = { "pack-objects", "--stdout", "-q", + use_ofs_delta ? "--delta-base-offset" : NULL, + NULL }; + + if (pipe(lp_pipe) < 0) + die("git-upload-pack: unable to create pipe"); + pack_pipe = fdopen(lp_pipe[1], "w"); + if (_beginthread(do_rev_list, 0, create_full_pack ? &create_full_pack : NULL) < 0) + die("git-upload-pack: unable to run rev-list: %s", strerror(errno)); + + if (pipe(pu_pipe) < 0) + die("git-upload-pack: unable to create pipe"); + + pid_pack_objects = spawnv_git_cmd(argv, lp_pipe, pu_pipe); + if (pid_pack_objects < 0) + die("git-upload-pack: unable to run git-pack-objects"); + + /* We read from pu_pipe[0] to capture the pack data. */ + + while ((sz = xread(pu_pipe[0], data+1, sizeof(data)-1)) > 0) { + cp = data+1; + /* Data ready; we keep the last byte to ourselves in case we + * detect broken rev-list, so that we can leave the stream + * corrupted. This is unfortunate -- unpack-objects would + * happily accept a valid pack data with trailing garbage, so + * appending garbage after we pass all the pack data is not + * good enough to signal breakage to downstream. + */ + if (0 <= buffered) { + *--cp = buffered; + sz++; + } + if (1 < sz) { + buffered = cp[sz-1] & 0xFF; + sz--; + } + else + buffered = -1; + sz = send_client_data(1, cp, sz); + if (sz < 0) + goto fail; + } + if (sz == 0) { + close(pu_pipe[0]); + pu_pipe[0] = -1; + } + else + goto fail; + + /* flush the data */ + if (0 <= buffered) { + data[0] = buffered; + sz = send_client_data(1, data, 1); + if (sz < 0) + goto fail; + fprintf(stderr, "flushed.\n"); + } + if (use_sideband) + packet_flush(1); + if (waitpid(pid_pack_objects, NULL, 0) < 0) + die("git-upload-pack: waiting for pack-objects: %s", + strerror(errno)); + return; + + fail: + kill(pid_pack_objects, SIGKILL); + send_client_data(3, abort_msg, sizeof(abort_msg)); + die("git-upload-pack: %s", abort_msg); +#endif } static int got_sha1(char *hex, unsigned char *sha1) From b61aae484eee63db583579db4ab4773b9e001b7e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 19 Jan 2007 13:16:58 +0100 Subject: [PATCH 0047/3720] Add a README.MinGW with instructions. --- README.MinGW | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 README.MinGW diff --git a/README.MinGW b/README.MinGW new file mode 100644 index 0000000000..ece360c806 --- /dev/null +++ b/README.MinGW @@ -0,0 +1,53 @@ +This is a port of GIT to Windows using MinGW. + +The goal of this port is to have the tools runnable from the Windows +command line, not from MinGW's rxvt+bash environment. + +(Note: This file was written after-the-fact and may contain errors. +If you are trying this, please make notes and update it.) + + +INSTALLATION +------------ + +In order to compile this code you need: + +- MSYS, e.g. MSYS-1.0.11-2004.04.30-1.exe +- MinGW, e.g. MinGW-5.0.2.exe +- mingwruntime, e.g. mingw-runtime-3.9.tar.gz +- compilers and tools: + binutils-2.15.91-20040904-1.tar.gz + gcc-core-3.4.2-20040916-1.tar.gz + gcc-g++-3.4.2-20040916-1.tar.gz + gdb-6.3-2.exe + mingw32-make-3.80.0-3.tar.gz + unzip-5.51-1-bin.zip (this is not from MinGW, iirc) +- additional libraries: + zlib-1.2.3-mingwPORT-1.tar + w32api-3.6.tar.gz + regex-0.12.tar.gz (from the GNU site) + compile this into regex.o, ar it into libregex.a + and install it in /mingw/lib, include file into + /mingw/include + tcltk-8.4.1-1.exe (for gitk, but it's untested so far) + +It is absolutely necessary that you install MSYS in a path that does not +contain special characters, like spaces. I have it in + + D:\MSYS\1.0 + D:\MSYS\1.0\mingw + +STATUS +------ + +This code base will not compile on a POSIX system, although any help +to introduce the necessary #ifdefs is welcome. As such the status quo +is in no way intended to be merged upstream. + +The toolset has only been used to run the test suite. +The plumbing that does the repository manipulation works, as well as +the porcelains that you need for daily (local!) work. + +pull, clone, fetch, do not work. This means that you must copy a repo +to your Windows using some plain copy instructions (be it Explorer +or command line). From cb0ad0c0af084b52a72791feeca7c70bd8ed855a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 15:11:29 +0200 Subject: [PATCH 0048/3720] fix t0000 for absence of symlinks --- Makefile | 2 ++ t/Makefile | 4 ++++ t/t0000-basic.sh | 32 ++++++++++++++++++++++++++++---- t/test-lib.sh | 2 ++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 105e2d1b6e..3144430a97 100644 --- a/Makefile +++ b/Makefile @@ -428,6 +428,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRLCPY=YesPlease NO_ICONV=YesPlease NO_C99_FORMAT = YesPlease + NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o @@ -832,6 +833,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS # However, the environment gets quite big, and some programs have problems # with that. +export NO_SYMLINKS export NO_SVN_TESTS test: all diff --git a/t/Makefile b/t/Makefile index 19e38508a7..8cca7120ce 100644 --- a/t/Makefile +++ b/t/Makefile @@ -13,6 +13,10 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) TSVN = $(wildcard t91[0-9][0-9]-*.sh) +ifdef NO_SYMLINKS + GIT_TEST_OPTS += --no-symlinks +endif + all: $(T) clean $(T): diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 186de70243..81ec70ff93 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -30,6 +30,22 @@ fi . ./test-lib.sh +test "$no_symlinks" && { + DIFF=$(which diff) + + function diff () { + opt= + case "$1" in -*) opt=$1; shift;; esac + tr -d "\015" < $1 > $1.doof + grep -v "^:\?120000" < $2 | \ + sed -e s/58a09c23e2ca152193f2786e06986b7b6712bdbe/600f42758e4458c37c2c1f8063378f540b4efad7/ \ + -e s/21ae8269cacbe57ae09138dcc3a2887f904d02b3/cfb8591b2f65de8b8cc1020cd7d9e67e7793b325/ \ + -e s/3c5e5399f3a333eddecce7a9b9465b63f65f51e2/ce580448f0148b985a513b693fdf7d802cacb44f/ \ + > $2.doof + $DIFF $opt $1.doof $2.doof + } +} + ################################################################ # git-init has been done in an empty repository. # make sure it is empty. @@ -113,6 +129,7 @@ cat >expected <<\EOF 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym EOF + test_expect_success \ 'validate git-ls-files output for a known tree.' \ 'diff current expected' @@ -120,9 +137,11 @@ test_expect_success \ test_expect_success \ 'writing tree out with git-write-tree.' \ 'tree=$(git-write-tree)' +expected_tree=087704a96baf1c2d1c869a8b084481e121c88b5b +test "$no_symlinks" && expected_tree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46 test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$tree" = 087704a96baf1c2d1c869a8b084481e121c88b5b' + 'test "$tree" = "$expected_tree"' test_expect_success \ 'showing tree with git-ls-tree' \ @@ -180,16 +199,20 @@ test_expect_success \ test_expect_success \ 'writing partial tree out with git-write-tree --prefix.' \ 'ptree=$(git-write-tree --prefix=path3)' +expected_tree=21ae8269cacbe57ae09138dcc3a2887f904d02b3 +test "$no_symlinks" && expected_tree=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325 test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3' + 'test "$ptree" = "$expected_tree"' test_expect_success \ 'writing partial tree out with git-write-tree --prefix.' \ 'ptree=$(git-write-tree --prefix=path3/subp3)' +expect_tree=3c5e5399f3a333eddecce7a9b9465b63f65f51e2 +test "$no_symlinks" && expect_tree=ce580448f0148b985a513b693fdf7d802cacb44f test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2' + 'test "$ptree" = "$expect_tree"' cat >badobjects <expected <<\EOF EOF test_expect_success \ 'validate git-diff-files output for a know cache/work tree state.' \ - 'git-diff-files >current && diff >/dev/null -b current expected' + 'git-diff-files >current && diff -b current expected' test_expect_success \ 'git-update-index --refresh should succeed.' \ @@ -246,6 +269,7 @@ test_expect_success \ ################################################################ P=087704a96baf1c2d1c869a8b084481e121c88b5b +test "$no_symlinks" && P=7bb943559a305bdd6bdee2cef6e5df2413c3d30a test_expect_success \ 'git-commit-tree records the correct tree in a commit.' \ 'commit0=$(echo NO | git-commit-tree $P) && diff --git a/t/test-lib.sh b/t/test-lib.sh index 8e3ee6cd7b..8bf0345ef6 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -78,6 +78,8 @@ do --no-python) # noop now... shift ;; + --no-symlinks) + no_symlinks=t; shift ;; *) break ;; esac From 3e70ecba72a43a06ce64cdec2396e663a62b22bc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 13:20:49 +0200 Subject: [PATCH 0049/3720] prepare more tests for lacking symlinks --- t/t2001-checkout-cache-clash.sh | 2 ++ t/t2003-checkout-cache-mkdir.sh | 4 ++++ t/t2004-checkout-cache-temp.sh | 2 ++ t/t2100-update-cache-badpath.sh | 2 ++ t/t3000-ls-files-others.sh | 1 + 5 files changed, 11 insertions(+) diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh index 0dcab8f1de..825119b01c 100755 --- a/t/t2001-checkout-cache-clash.sh +++ b/t/t2001-checkout-cache-clash.sh @@ -59,10 +59,12 @@ test_expect_success \ 'git-read-tree -m $tree1 && git-checkout-index -f -a' test_debug 'show_files $tree1' +test "$no_symlinks" || { ln -s path0 path1 test_expect_success \ 'git-update-index --add a symlink.' \ 'git-update-index --add path1' +} test_expect_success \ 'writing tree out with git-write-tree' \ 'tree3=$(git-write-tree)' diff --git a/t/t2003-checkout-cache-mkdir.sh b/t/t2003-checkout-cache-mkdir.sh index f9bc90aee4..6aa00f8edb 100755 --- a/t/t2003-checkout-cache-mkdir.sh +++ b/t/t2003-checkout-cache-mkdir.sh @@ -19,6 +19,7 @@ test_expect_success \ echo rezrov >path1/file1 && git-update-index --add path0 path1/file1' +test "$no_symlinks" || { test_expect_success \ 'have symlink in place where dir is expected.' \ 'rm -fr path0 path1 && @@ -27,6 +28,7 @@ test_expect_success \ git-checkout-index -f -a && test ! -h path1 && test -d path1 && test -f path1/file1 && test ! -f path2/file1' +} test_expect_success \ 'use --prefix=path2/' \ @@ -58,6 +60,7 @@ test_expect_success \ test ! -f path0 && test ! -f path1/file1' +test "$no_symlinks" || { # Linus fix #1 test_expect_success \ 'use --prefix=tmp/orary/ where tmp is a symlink' \ @@ -92,5 +95,6 @@ test_expect_success \ test ! -h tmp-path1 && test -d tmp-path1 && test -f tmp-path1/file1' +} test_done diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh index c100959cad..1bf63d37e7 100755 --- a/t/t2004-checkout-cache-temp.sh +++ b/t/t2004-checkout-cache-temp.sh @@ -194,6 +194,7 @@ test_expect_success \ test $(cat ../$s1) = tree1asubdir/path5) )' +test "$no_symlinks" || { test_expect_success \ 'checkout --temp symlink' ' rm -f path* .merge_* out .git/index && @@ -208,5 +209,6 @@ test $(cut "-d " -f2 out) = a && p=$(cut "-d " -f1 out) && test -f $p && test $(cat $p) = b' +} test_done diff --git a/t/t2100-update-cache-badpath.sh b/t/t2100-update-cache-badpath.sh index 5bc0a3bed3..cc3bd9f775 100755 --- a/t/t2100-update-cache-badpath.sh +++ b/t/t2100-update-cache-badpath.sh @@ -29,6 +29,7 @@ date >path0 ln -s xyzzy path1 date >path2/file2 date >path3/file3 +test "$no_symlinks" && date > path1 test_expect_success \ 'git-update-index --add to add various paths.' \ @@ -41,6 +42,7 @@ date >path2 ln -s frotz path3 date >path0/file0 date >path1/file1 +test "$no_symlinks" && date > path3 for p in path0/file0 path1/file1 path2 path3 do diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index adcbe03d56..b470eb46be 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -18,6 +18,7 @@ filesystem. date >path0 ln -s xyzzy path1 +test "$no_symlinks" && date > path1 mkdir path2 path3 date >path2/file2 date >path2-junk From 8e128cd8c18d3cac811b9d70ee8b34fc1eae8785 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 17:34:43 +0200 Subject: [PATCH 0050/3720] fix more tests for lacking symlinks --- t/t3010-ls-files-killed-modified.sh | 7 +++++++ t/t3100-ls-tree-restrict.sh | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh index 5fc1976711..bf5b20f8a3 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -37,6 +37,13 @@ modified without reporting path9 and path10. ' . ./test-lib.sh +test "$no_symlinks" && { + function ln () { + test "$1" = -s && shift + date > "$2" + } +} + date >path0 ln -s xyzzy path1 mkdir path2 path3 diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 2ec06d3d39..33df0f95eb 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -18,6 +18,24 @@ path2/baz. Also path0/ should snow nothing. ' . ./test-lib.sh +test "$no_symlinks" && { + function ln () { + test "$1" = -s && shift + date > "$2" + } + DIFF=$(which diff) + function diff () { + opt= + if test "$1" = -u; then + opt="$1" + shift + fi + sed s/^120000/100644/ < "$1" > "$1".doof + $DIFF $opt "$1".doof "$2" + } +} + + test_expect_success \ 'setup' \ 'mkdir path2 path2/baz && From 6e5bd6187c3ad2529a85f1ea063b13695c05b91b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:29:04 +0100 Subject: [PATCH 0051/3720] Even more tests to skip due to missing symbolic link support. --- t/t3200-branch.sh | 2 ++ t/t4004-diff-rename-symlink.sh | 7 +++++++ t/t4008-diff-break-rewrite.sh | 4 ++++ t/t4011-diff-symlink.sh | 7 +++++++ t/t4115-apply-symlink.sh | 7 +++++++ t/t5000-tar-tree.sh | 7 +++++++ 6 files changed, 34 insertions(+) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index bb80e4286a..258b0c1658 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -110,11 +110,13 @@ test_expect_success 'config information was renamed, too' \ "test $(git-repo-config branch.s.dummy) = Hello && ! git-repo-config branch.s/s/dummy" +test "$no_symlinks" || { test_expect_failure \ 'git-branch -m u v should fail when the reflog for u is a symlink' \ 'git-branch -l u && mv .git/logs/refs/heads/u real-u && ln -s real-u .git/logs/refs/heads/u && git-branch -m u v' +} test_done diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh index a23aaa0a94..61b0fc7cab 100755 --- a/t/t4004-diff-rename-symlink.sh +++ b/t/t4004-diff-rename-symlink.sh @@ -12,6 +12,13 @@ by an edit for them. . ./test-lib.sh . ../diff-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success \ 'prepare reference tree' \ 'echo xyzzy | tr -d '\\\\'012 >yomin && diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh index 263ac1ebf7..f0c853af29 100755 --- a/t/t4008-diff-break-rewrite.sh +++ b/t/t4008-diff-break-rewrite.sh @@ -99,6 +99,8 @@ test_expect_success \ 'validate result of -B -M (#4)' \ 'compare_diff_raw expected current' +test "$no_symlinks" || { + test_expect_success \ 'make file0 into something completely different' \ 'rm -f file0 && @@ -148,6 +150,8 @@ test_expect_success \ 'validate result of -M (#7)' \ 'compare_diff_raw expected current' +} # end symlink tests + test_expect_success \ 'file1 edited to look like file0 and file0 rename-edited to file2' \ 'rm -f file0 file1 && diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index 379a831f0b..2e415c0816 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -9,6 +9,13 @@ test_description='Test diff of symlinks. . ./test-lib.sh . ../diff-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + cat > expected << EOF diff --git a/frotz b/frotz new file mode 120000 diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index d5f2cfb186..524d72f0dd 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -9,6 +9,13 @@ test_description='git-apply symlinks and partial files . ./test-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success setup ' ln -s path1/path2/path3/path4/path5 link1 && diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index cf08e9279c..fcfa7e4e41 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -28,6 +28,13 @@ commit id embedding: TAR=${TAR:-tar} UNZIP=${UNZIP:-unzip} +test "$no_symlinks" && { + function ln () { + test "$1" = -s && shift + date > "$2" + } +} + test_expect_success \ 'populate workdir' \ 'mkdir a b c && From f603a1c5620c6d1bca4ca084638a72b67aff07c6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:29:35 +0100 Subject: [PATCH 0052/3720] Use the git wrapper to invoke git commit. --- t/t3400-rebase.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index b9d3131cc2..1c728c8459 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -15,15 +15,15 @@ test_expect_success \ 'prepare repository with topic branch, then rebase against master' \ 'echo First > A && git-update-index --add A && - git-commit -m "Add A." && + git commit -m "Add A." && git checkout -b my-topic-branch && echo Second > B && git-update-index --add B && - git-commit -m "Add B." && + git commit -m "Add B." && git checkout -f master && echo Third >> A && git-update-index A && - git-commit -m "Modify A." && + git commit -m "Modify A." && git checkout -f my-topic-branch && git rebase master' From 32713b461256c42abd829ca62774649eb7182855 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:38:32 +0100 Subject: [PATCH 0053/3720] Work around missing tools on MinGW. egrep cannot be called from the Windows command line. dd and sum are not available. --- t/t1002-read-tree-m-u-2way.sh | 6 ++++++ t/t3800-mktag.sh | 2 +- t/t5300-pack-object.sh | 30 +++++++++++++++++++++--------- t/t5301-sliding-window.sh | 4 ++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index da3c81357b..6012df56eb 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -10,6 +10,12 @@ This is identical to t1001, but uses -u to update the work tree as well. ' . ./test-lib.sh +sum ./test-lib.sh >/dev/null 2>&1 || { + function sum () { + md5sum "$@" + } +} + _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh index ede4d42495..d45e10d026 100755 --- a/t/t3800-mktag.sh +++ b/t/t3800-mktag.sh @@ -15,7 +15,7 @@ check_verify_failure () { test_expect_success \ "$1" \ 'git-mktag message || - egrep -q -f expect.pat message' + grep -E -q -f expect.pat message' } ########################################################### diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 622c5f9968..508803a8e0 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -10,12 +10,28 @@ test_description='git-pack-object TRASH=`pwd` +x4k=xxxxxxxx +x4k="$x4k$x4k$x4k$x4k$x4k$x4k$x4k$x4k" +x4k="$x4k$x4k$x4k$x4k$x4k$x4k$x4k$x4k" +x4k="$x4k$x4k$x4k$x4k$x4k$x4k$x4k$x4k" + +corrupt() +{ + ( + read -d "" -n $4 l + echo -n "$l" + read -d "" -n $3 l + echo -n ${x4k:0:$3} | tr x '\0' + cat + ) < $1 > $2 +} + test_expect_success \ 'setup' \ 'rm -f .git/index* for i in a b c do - dd if=/dev/zero bs=4k count=1 | tr "\\0" $i >$i && + echo -n "$x4k" | tr x $i >$i && git-update-index --add $i || return 1 done && cat c >d && echo foo >>d && git-update-index --add d && @@ -144,8 +160,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted pack signature' \ - 'cp test-1-${packname_1}.pack test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=2 && + 'corrupt test-1-${packname_1}.pack test-3.pack 1 2 && if git-verify-pack test-3.idx then false else :; @@ -153,8 +168,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted pack version' \ - 'cp test-1-${packname_1}.pack test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=7 && + 'corrupt test-1-${packname_1}.pack test-3.pack 1 7 && if git-verify-pack test-3.idx then false else :; @@ -162,8 +176,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted type/size of the 1st packed object data' \ - 'cp test-1-${packname_1}.pack test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=12 && + 'corrupt test-1-${packname_1}.pack test-3.pack 1 12 && if git-verify-pack test-3.idx then false else :; @@ -173,8 +186,7 @@ test_expect_success \ 'verify-pack catches a corrupted sum of the index file itself' \ 'l=`wc -c Date: Mon, 8 Jan 2007 18:40:11 +0100 Subject: [PATCH 0054/3720] Work around CF-LF mismatches introduced by non-MinGW tools. --- t/t1003-read-tree-prefix.sh | 4 ++++ t/t4109-apply-multifrag.sh | 4 ++++ t/t4110-apply-scan.sh | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh index 48ab117d75..1c595f18bb 100755 --- a/t/t1003-read-tree-prefix.sh +++ b/t/t1003-read-tree-prefix.sh @@ -8,6 +8,10 @@ test_description='git-read-tree --prefix test. . ./test-lib.sh +cmp () { + diff -w "$@" +} + test_expect_success setup ' echo hello >one && git-update-index --add one && diff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh index 5988e1ae4c..20f46fc1ca 100755 --- a/t/t4109-apply-multifrag.sh +++ b/t/t4109-apply-multifrag.sh @@ -9,6 +9,10 @@ test_description='git-apply test patches with multiple fragments. ' . ./test-lib.sh +cmp () { + diff -w "$@" +} + # setup cat > patch1.patch <<\EOF diff --git a/t/t4110-apply-scan.sh b/t/t4110-apply-scan.sh index 005f744816..c7cbe4ef64 100755 --- a/t/t4110-apply-scan.sh +++ b/t/t4110-apply-scan.sh @@ -9,6 +9,10 @@ test_description='git-apply test for patches which require scanning forwards and ' . ./test-lib.sh +cmp () { + diff -w "$@" +} + # setup cat > patch1.patch <<\EOF From 306e27d8ee4d61584c0bd6d4b46daabc1f95095b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Jan 2007 14:18:14 +0100 Subject: [PATCH 0055/3720] Recommend msysDTK for perl and ssh. --- README.MinGW | 1 + 1 file changed, 1 insertion(+) diff --git a/README.MinGW b/README.MinGW index ece360c806..8c704052e8 100644 --- a/README.MinGW +++ b/README.MinGW @@ -22,6 +22,7 @@ In order to compile this code you need: gdb-6.3-2.exe mingw32-make-3.80.0-3.tar.gz unzip-5.51-1-bin.zip (this is not from MinGW, iirc) + msysDTK-1.0.1.exe (contains ssh, perl) - additional libraries: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz From 562cd8385d5ebc4461cef15a91997dd0a4cd1666 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Jan 2007 14:19:23 +0100 Subject: [PATCH 0056/3720] In the host:/path notation require 'host' to be at least 2 chars long. This is necessary to distinguish the notation from the DOS-style C:/path notation with a drive letter. --- connect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index 171f34837f..d3964b8059 100644 --- a/connect.c +++ b/connect.c @@ -680,7 +680,8 @@ pid_t git_connect(int fd[2], char *url, const char *prog) path = strchr(end, c); if (c == ':') { - if (path) { + /* host must have at least 2 chars to catch DOS C:/path */ + if (path && path - end > 1) { protocol = PROTO_SSH; *path++ = '\0'; } else From d576539c9255d22425efcc55f7e9720fbb8a42d1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Jan 2007 17:06:51 +0100 Subject: [PATCH 0057/3720] Do not skip the initialization of the date string. Due to some rebasing in the past, new functions that have been introduced upstream moved into the MinGW portion of the #ifdefs just by coincidend, but the initialization of the date string remained in the original spot. The consequence was that all commits that did not use GIT_*_DATE were created with an empty date part. This removes the second instance of setup_ident(), which was lacking the initialization. --- ident.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/ident.c b/ident.c index 83ce631a06..145f54a505 100644 --- a/ident.c +++ b/ident.c @@ -45,8 +45,11 @@ static void copy_gecos(struct passwd *w, char *name, int sz) } +#endif + int setup_ident(void) { +#ifndef NO_ETC_PASSWD int len; struct passwd *pw = getpwuid(getuid()); @@ -74,13 +77,12 @@ int setup_ident(void) else strlcpy(git_default_email + len, "(none)", sizeof(git_default_email) - len); } +#endif /* And set the default date */ datestamp(git_default_date, sizeof(git_default_date)); return 0; } -#else /* NO_ETC_PASSWD */ - static int add_raw(char *buf, int size, int offset, const char *str) { int len = strlen(str); @@ -156,13 +158,6 @@ static int copy(char *buf, int size, int offset, const char *src) return offset; } -int setup_ident(void) -{ - return 0; -} - -#endif - static const char au_env[] = "GIT_AUTHOR_NAME"; static const char co_env[] = "GIT_COMMITTER_NAME"; static const char *env_hint = From 6397c3119ecaa258b5185315c64062bec29bcd86 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Jan 2007 10:06:25 +0100 Subject: [PATCH 0058/3720] Expect absolute paths with a drive letter. This allows the alternates database to refer to other object databases via a DOS-like path with a drive letter. Furthermore, update-ref sometimes operates on absolute paths. --- sha1_file.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index 14ec604797..7146699c0b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -80,14 +80,22 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) return 0; } +/* returns the number of chars to skip to first component */ +static inline int is_path_absolute(const char *path) +{ +#ifdef __MINGW32__ + if (isalpha(path[0]) && path[1] == ':') + return 2 + (path[2] == '/'); + /* TODO: C:dir/file 'relative' paths are not catered for */ +#endif + return *path == '/'; +} + int safe_create_leading_directories(char *path) { - char *pos = path; + char *pos = path + is_path_absolute(path); struct stat st; - if (*pos == '/') - pos++; - while (pos) { pos = strchr(pos, '/'); if (!pos) @@ -252,7 +260,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative int entlen = pfxlen + 43; int base_len = -1; - if (*entry != '/' && relative_base) { + if (!is_path_absolute(entry) && relative_base) { /* Relative alt-odb */ if (base_len < 0) base_len = strlen(relative_base) + 1; @@ -261,7 +269,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative } ent = xmalloc(sizeof(*ent) + entlen); - if (*entry != '/' && relative_base) { + if (!is_path_absolute(entry) && relative_base) { memcpy(ent->base, relative_base, base_len - 1); ent->base[base_len - 1] = '/'; memcpy(ent->base + base_len, entry, len); @@ -332,7 +340,7 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep, while (cp < ep && *cp != sep) cp++; if (last != cp) { - if ((*last != '/') && depth) { + if (!is_path_absolute(last) && depth) { error("%s: ignoring relative alternate object store %s", relative_base, last); } else { From 5bc08ee66f49beedb5327446ff147e92345df65c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Jan 2007 13:20:18 +0100 Subject: [PATCH 0059/3720] Strip \r from the input. Sometimes CRLF ends up in FETCH_HEAD. As a consequence, the fetch source '.' is not recognized as a special case. --- builtin-fmt-merge-msg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index 87d3d63ec7..252c7eb4b5 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -95,6 +95,8 @@ static int handle_line(char *line) return 3; if (line[len - 1] == '\n') + line[len - 1] = 0, --len; + if (line[len - 1] == '\r') line[len - 1] = 0; line += 42; From e40c594146c4368e43ce823df6dcc89589b8e547 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 23 Jan 2007 13:39:09 +0100 Subject: [PATCH 0060/3720] mingw: always chmod(, 0666) before unlink() On Windows, a read-only file cannot be deleted. To make sure that deletion does not fail because of this, always call chmod() before unlink(). Signed-off-by: Johannes Schindelin --- git-compat-util.h | 7 +++++++ index-pack.c | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index bf42191ab7..4c3250858b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -359,6 +359,13 @@ static inline int git_mkdir(const char *path, int mode) } #define mkdir git_mkdir +static inline int git_unlink(const char *pathname) { + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} +#define unlink git_unlink + #include struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); diff --git a/index-pack.c b/index-pack.c index 040957c016..72e0962415 100644 --- a/index-pack.c +++ b/index-pack.c @@ -700,10 +700,6 @@ static const char *write_index_file(const char *index_name, unsigned char *sha1) fd = mkstemp(tmpfile); index_name = xstrdup(tmpfile); } else { -#ifdef __MINGW32__ - /* read-only files cannot be removed */ - chmod(index_name, 0666); -#endif unlink(index_name); fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600); } From 45c0d8773de8636ce6822b27b82ebf0935cb64e0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Jan 2007 14:19:48 +0100 Subject: [PATCH 0061/3720] Remove the unused strptime() stub. strptime() is only used in convert-objects.c, but we do not build that one (for reasons I do not recall anymore). That tool should be unnecessary anyway. --- compat/mingw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6d067c9450..f5b64fc564 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -164,13 +164,11 @@ char *mingw_getcwd(char *pointer, int len) } return ret; } -const char *strptime(char *buf, const char *format, struct tm *tm) -{ - die("MinGW does not yet support strptime!"); -} + void sync(void) { } + void openlog(const char *ident, int option, int facility) { } From 58352818740fff00666d23e8eaa102de1eb54747 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Jan 2007 14:45:09 +0100 Subject: [PATCH 0062/3720] Clean up another instance of unlink that was explicitly chmod(, 0666)ed. --- builtin-prune-packed.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 639fbed2fc..6473d327e6 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -26,10 +26,6 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) if (opts & DRY_RUN) printf("rm -f %s\n", pathname); else { -#ifdef __MINGW32__ - /* read-only files cannot be removed */ - chmod(pathname, 0666); -#endif if (unlink(pathname) < 0) error("unable to unlink %s", pathname); } From 28b06b3aab31c91237788e394cfc4771f029b355 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 09:08:11 +0100 Subject: [PATCH 0063/3720] Simplify the cpio look-alike. We don't need to write the file list into a temporary file, because GNU tar can take --files-from stdin in --create mode. Furthermore, it understands --null, so that we don't need to translate the zero byte termination to newlines (which incorrectly had been translated to space). --- cpio.sh | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/cpio.sh b/cpio.sh index a0a5a372f2..0b219fa729 100644 --- a/cpio.sh +++ b/cpio.sh @@ -7,11 +7,11 @@ die() { exit 1 } -tr0=cat +null= while test $# -gt 0; do case "$1" in - -0) tr0="tr '\0' ' '";; + -0) null=--null;; -o) mode=o;; -iuv) ;; -pumd|-pumdl) @@ -26,20 +26,12 @@ done case $mode in o) - files=.cpiofiles$$ - $tr0 > $files - tar --create --file=- --files-from=$files --exclude=$files - rc=$? - rm -f $files - exit $rc + tar --create --file=- $null --files-from=- ;; p) - files=.cpiofiles$$ - $tr0 > $files - tar --create --file=- --files-from=$files --exclude=$files | + tar --create --file=- $null --files-from=- | tar --extract --directory="$dir" --file=- - rm -f $files ;; *) - tar xvf - || exit + tar xvf - esac From 4feaf032d3c2e144e0dca61e004481164dace56a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 09:37:48 +0100 Subject: [PATCH 0064/3720] Do not complain if no committer identifier can be written to the reflog. git clone leaves a half-baked clone without the HEAD ref and no working tree, but with the full repository, if it cannot find the committer information in the GECOS field. For a first-time user this may be puzzling since git clone may be the very first git command to be tried. The reflog is entirely local information, and the warning about the missing information is printed anyway, so there is a hint for the user how to fill it in. --- refs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/refs.c b/refs.c index 7d858637c4..d6c717f1c9 100644 --- a/refs.c +++ b/refs.c @@ -958,7 +958,7 @@ static int log_ref_write(struct ref_lock *lock, lock->log_file, strerror(errno)); } - committer = git_committer_info(1); + committer = git_committer_info(0); if (msg) { maxlen = strlen(committer) + strlen(msg) + 2*40 + 5; logrec = xmalloc(maxlen); From 18bf4a4beafb904ab0ee2fcb3a59b7d95f42c9ef Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 10:46:24 +0100 Subject: [PATCH 0065/3720] Cpio emulator: do not copy files repeatedly in pass-through mode. Files were stored each time when they were mentioned in the file list as well as for each of its directories and parent directories. Now we filter out directory names because they are implied for the files that they contain, but we do list empty directories. The only case where this is relevant is the pass-through mode that git clone of a local directory uses. --- cpio.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/cpio.sh b/cpio.sh index 0b219fa729..2816e34851 100644 --- a/cpio.sh +++ b/cpio.sh @@ -24,12 +24,27 @@ while test $# -gt 0; do shift done +filterdirs() { + while read f; do + if test -d "$f"; then + # list only empty directories + if test -z "$(ls -A "$f")"; then + echo "$f" + fi + else + echo "$f" + fi + done +} + case $mode in o) tar --create --file=- $null --files-from=- ;; p) - tar --create --file=- $null --files-from=- | + test -z "$null" || die "cpio: cannot use -0 in pass-through mode" + filterdirs | + tar --create --file=- --files-from=- | tar --extract --directory="$dir" --file=- ;; *) From 8c5c2ae8fca650b5d0214fff95d611a6b099ca16 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 13:13:14 +0100 Subject: [PATCH 0066/3720] Update the status part of README.MinGW. pull, fetch, clone work to a large extent. Hurray! --- README.MinGW | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/README.MinGW b/README.MinGW index 8c704052e8..ebd7c0c2ba 100644 --- a/README.MinGW +++ b/README.MinGW @@ -45,10 +45,34 @@ This code base will not compile on a POSIX system, although any help to introduce the necessary #ifdefs is welcome. As such the status quo is in no way intended to be merged upstream. -The toolset has only been used to run the test suite. -The plumbing that does the repository manipulation works, as well as -the porcelains that you need for daily (local!) work. +This works: -pull, clone, fetch, do not work. This means that you must copy a repo -to your Windows using some plain copy instructions (be it Explorer -or command line). +- All the plumbings. +- Many porcelains, in particular, checkout, add, rm, commit, diff, + branch, merge, rebase, log, show, bisect, grep... +- pull, clone, fetch via ssh. +- local pull, clone, fetch. +- gitk, if invoked as "wish84 \bin\gitk", but there are + artefacts in its layout. + +This does not work: + +- pull, clone, fetch via native GIT protocol. +- push +- blame +- daemon, svn, *import, cvs* +- and certainly a lot more that I never have found a need to look at. + +Caveats (aka bugs): + +- The automatic pager of commands like log or diff does not work + correctly: It does not display some portion of text at the end. + That is, if what you should see is less than 4K, you see nothing at + all; otherwise something up to 4K at the end is missing. Use + `git log | less' in these cases. Or `set PAGER=cat' (which is + optimized to skip the pager entirely). +- Internally, the ported tools must do their own command line quoting + when other plumbings are executed. This sort of quoting is currently + implemented *very* simplistic: It just watches out for whitespace + and double quote `"' characters. This may become a problem if you have + exotic characters in your file names. From 46580d2192d79a469f8b40fc1081db9116ad5517 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 16:03:42 +0100 Subject: [PATCH 0067/3720] Add a missing fork() error check. --- send-pack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/send-pack.c b/send-pack.c index 6756264b29..4bf9466610 100644 --- a/send-pack.c +++ b/send-pack.c @@ -25,6 +25,8 @@ static int pack_objects(int fd, struct ref *refs) if (pipe(pipe_fd) < 0) return error("send-pack: pipe failed"); pid = fork(); + if (pid < 0) + return error("send-pack: unable to fork git-pack-objects"); if (!pid) { /* * The child becomes pack-objects --revs; we feed From 2033ba137a361d0d36c644de45e3d01578a4b77c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 17:06:21 +0100 Subject: [PATCH 0068/3720] Use spawn*_pipe() instead of fork()/exec() in send-pack and receive-pack. --- receive-pack.c | 10 +--------- send-pack.c | 45 ++++++++++++++++++--------------------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/receive-pack.c b/receive-pack.c index cf83109859..5690f9985c 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -325,17 +325,9 @@ static const char *unpack(void) if (pipe(fd) < 0) return "index-pack pipe failed"; - pid = fork(); + pid = spawnv_git_cmd(keeper, NULL, fd); if (pid < 0) return "index-pack fork failed"; - if (!pid) { - dup2(fd[1], 1); - close(fd[1]); - close(fd[0]); - execv_git_cmd(keeper); - die("execv of index-pack failed"); - } - close(fd[1]); /* * The first thing we expects from index-pack's output diff --git a/send-pack.c b/send-pack.c index 4bf9466610..d1e1372041 100644 --- a/send-pack.c +++ b/send-pack.c @@ -20,44 +20,35 @@ static int use_thin_pack; static int pack_objects(int fd, struct ref *refs) { int pipe_fd[2]; + int pack_fd[2] = { -1, fd }; pid_t pid; + /* + * The child becomes pack-objects --revs; we feed + * the revision parameters to it via its stdin and + * let its stdout go back to the other end. + */ + static const char *args[] = { + "pack-objects", + "--all-progress", + "--revs", + "--stdout", + NULL, + NULL, + }; + if (use_thin_pack) + args[4] = "--thin"; + if (pipe(pipe_fd) < 0) return error("send-pack: pipe failed"); - pid = fork(); + pid = spawnv_git_cmd(args, pipe_fd, pack_fd); if (pid < 0) return error("send-pack: unable to fork git-pack-objects"); - if (!pid) { - /* - * The child becomes pack-objects --revs; we feed - * the revision parameters to it via its stdin and - * let its stdout go back to the other end. - */ - static const char *args[] = { - "pack-objects", - "--all-progress", - "--revs", - "--stdout", - NULL, - NULL, - }; - if (use_thin_pack) - args[4] = "--thin"; - dup2(pipe_fd[0], 0); - dup2(fd, 1); - close(pipe_fd[0]); - close(pipe_fd[1]); - close(fd); - execv_git_cmd(args); - die("git-pack-objects exec failed (%s)", strerror(errno)); - } /* * We feed the pack-objects we just spawned with revision * parameters by writing to the pipe. */ - close(pipe_fd[0]); - close(fd); while (refs) { char buf[42]; From 10c1047e091e93854a5df231b4bf6b2ebdc51d41 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 18:48:14 +0100 Subject: [PATCH 0069/3720] Fix path_lookup() when the program to invoke contains a slash. In this case, no path lookup actually takes place, and the returned program name is equal to the passed in program name. But this code path contained a thinko that crashed. --- spawn-pipe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spawn-pipe.c b/spawn-pipe.c index b828809820..b4c2538b04 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -79,9 +79,9 @@ static char *path_lookup(const char *cmd, char **path) int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); if (strchr(cmd, '/') || strchr(cmd, '\\')) - p = NULL; + prog = xstrdup(cmd); - while (*p && !prog) { + while (!prog && *p) { prog = lookup_prog(*p++, cmd, tryexe); } if (!prog) { From daabe66f1811adc90825a75ff1b4116e4e7f4a4c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 25 Jan 2007 09:17:06 +0100 Subject: [PATCH 0070/3720] MinGW: Change the name of hook scripts to make them not executable by default. Since on Windows there is no 'executable' bit whose absence would deny execution of a script, we must change the hook scripts' names entirely to inhibit that they can be invoked by the tools. --- Makefile | 3 ++- templates/Makefile | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3144430a97..7e4fed4416 100644 --- a/Makefile +++ b/Makefile @@ -434,6 +434,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o EXTLIBS += -lws2_32 -lregex X = .exe + NOEXECTEMPL = .noexec endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease @@ -635,7 +636,7 @@ endif all:: $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all - $(MAKE) -C templates + $(MAKE) -C templates NOEXECTEMPL='$(NOEXECTEMPL)' strip: $(PROGRAMS) git$X $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X diff --git a/templates/Makefile b/templates/Makefile index 9e1ae1a4e0..68614c1cc7 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -5,6 +5,8 @@ TAR ?= tar prefix ?= $(HOME) template_dir ?= $(prefix)/share/git-core/templates/ # DESTDIR= +# set NOEXECTEMPL to non-empty to change the names of hook scripts +# so that the tools will not find them # Shell quote (do not use $(call) to accomodate ancient setups); DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) @@ -27,7 +29,11 @@ boilerplates.made : $(bpsrc) mkdir -p blt/$$dir && \ case "$$boilerplate" in \ *--) ;; \ - *) cp $$boilerplate blt/$$dst ;; \ + *) if head -1 $$boilerplate | grep -q '^#!/'; then \ + cp $$boilerplate blt/$${dst}$(NOEXECTEMPL); \ + else \ + cp $$boilerplate blt/$$dst; \ + fi ;; \ esac || exit; \ done || exit date >$@ From 479be60605163c7befec1880c72e2cbf584cf206 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 25 Jan 2007 11:12:37 +0100 Subject: [PATCH 0071/3720] Use spawn*_pipe() instead of fork()/exec() in run_command_*(). --- run-command.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/run-command.c b/run-command.c index cfbad74d14..eb6fefb98b 100644 --- a/run-command.c +++ b/run-command.c @@ -1,28 +1,31 @@ #include "cache.h" #include "run-command.h" #include "exec_cmd.h" +#include "spawn-pipe.h" int run_command_v_opt(const char **argv, int flags) { - pid_t pid = fork(); + pid_t pid; + int fd_i[2] = { -1, -1 }; + int fd_o[2] = { -1, -1 }; + if (flags & RUN_COMMAND_NO_STDIN) { +#ifndef __MINGW32__ + fd_i[0] = open("/dev/null", O_RDWR); +#else + fd_i[0] = open("nul", O_RDWR); +#endif + } + if (flags & RUN_COMMAND_STDOUT_TO_STDERR) + fd_o[1] = dup(2); + + if (flags & RUN_GIT_CMD) { + pid = spawnv_git_cmd(argv, fd_i, fd_o); + } else { + pid = spawnvpe_pipe(argv[0], argv, environ, fd_i, fd_o); + } if (pid < 0) return -ERR_RUN_COMMAND_FORK; - if (!pid) { - if (flags & RUN_COMMAND_NO_STDIN) { - int fd = open("/dev/null", O_RDWR); - dup2(fd, 0); - close(fd); - } - if (flags & RUN_COMMAND_STDOUT_TO_STDERR) - dup2(2, 1); - if (flags & RUN_GIT_CMD) { - execv_git_cmd(argv); - } else { - execvp(argv[0], (char *const*) argv); - } - die("exec %s failed.", argv[0]); - } for (;;) { int status, code; pid_t waiting = waitpid(pid, &status, 0); From 62404b843d5a180527aed2007c13a10e6c8b2fa5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 25 Jan 2007 11:31:31 +0100 Subject: [PATCH 0072/3720] README.MinGW: push works now locally and via ssh! --- README.MinGW | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.MinGW b/README.MinGW index ebd7c0c2ba..0f15eaf92c 100644 --- a/README.MinGW +++ b/README.MinGW @@ -50,15 +50,14 @@ This works: - All the plumbings. - Many porcelains, in particular, checkout, add, rm, commit, diff, branch, merge, rebase, log, show, bisect, grep... -- pull, clone, fetch via ssh. -- local pull, clone, fetch. +- pull, clone, fetch, push via ssh. +- local pull, clone, fetch, push. - gitk, if invoked as "wish84 \bin\gitk", but there are artefacts in its layout. This does not work: -- pull, clone, fetch via native GIT protocol. -- push +- pull, clone, fetch, push via native GIT protocol. - blame - daemon, svn, *import, cvs* - and certainly a lot more that I never have found a need to look at. From 273855b70fd6fcf14a4d77d3bee13bffc22188da Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 25 Jan 2007 14:56:02 +0100 Subject: [PATCH 0073/3720] spawnvppe_pipe(): Don't die on error, some callers want to handle it. --- connect.c | 7 ++++++- diff.c | 2 ++ merge-index.c | 3 +++ spawn-pipe.c | 3 --- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/connect.c b/connect.c index 64222f9ad9..3612c5538c 100644 --- a/connect.c +++ b/connect.c @@ -624,8 +624,11 @@ static void git_proxy_connect(int fd[2], char *host) { const char *argv[] = { NULL, host, port, NULL }; - spawnvpe_pipe(git_proxy_command, argv, environ, pipefd[1], pipefd[0]); + pid = spawnvpe_pipe(git_proxy_command, argv, environ, + pipefd[1], pipefd[0]); } + if (pid < 0) + die("fork failed"); fd[0] = pipefd[0][0]; fd[1] = pipefd[1][1]; } @@ -761,6 +764,8 @@ pid_t git_connect(int fd[2], char *url, const char *prog) env_unsetenv(env, INDEX_ENVIRONMENT); pid = spawnvpe_pipe("sh", argv, env, pipefd[1], pipefd[0]); } + if (pid < 0) + die("unable to fork"); fd[0] = pipefd[0][0]; fd[1] = pipefd[1][1]; if (free_path) diff --git a/diff.c b/diff.c index 12161b6f87..224d369288 100644 --- a/diff.c +++ b/diff.c @@ -1500,6 +1500,8 @@ static int spawn_prog(const char *pgm, const char **arg) fflush(NULL); pid = spawnvpe_pipe(pgm, arg, environ, NULL, NULL); + if (pid < 0) + die("unable to fork"); while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) diff --git a/merge-index.c b/merge-index.c index 6c2e00842e..bc85e35f4d 100644 --- a/merge-index.c +++ b/merge-index.c @@ -11,6 +11,9 @@ static void run_program(void) pid_t pid = spawnvpe_pipe(pgm, arguments, environ, NULL, NULL); int status; + if (pid < 0) + die("unable to fork"); + if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) { if (one_shot) { err++; diff --git a/spawn-pipe.c b/spawn-pipe.c index b4c2538b04..7d8aa7d6c7 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -198,9 +198,6 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, pid = spawnvpe(_P_NOWAIT, interpr, qargv, env); } - if (pid < 0) - die("unable to run %s", cmd); - free(qargv); /* TODO: quoted args should be freed, too */ free(prog); From 8c8bb94f94f1d972c7ffadda4744cf343fac6f34 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 26 Jan 2007 14:41:01 +0100 Subject: [PATCH 0074/3720] gitk: Use peek-remote instead of ls-remote. git --git-dir is certainly always local, so there is no need to ask for the advanced services of ls-remote. --- gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk b/gitk index 031c829f26..e415915b74 100755 --- a/gitk +++ b/gitk @@ -309,7 +309,7 @@ proc readrefs {} { foreach v {tagids idtags headids idheads otherrefids idotherrefs} { catch {unset $v} } - set refd [open [list | git ls-remote [gitdir]] r] + set refd [open [list | git peek-remote [gitdir]] r] while {0 <= [set n [gets $refd line]]} { if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \ match id path]} { From f002a73f048a49c75b9d808b96bf84cbb630113c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 29 Jan 2007 13:41:10 +0100 Subject: [PATCH 0075/3720] Implement a usable gettimeofday(). For simplicity, my_mktime() of date.c is reused to avoid the convolutions that gmtime() and localtime() would implicate. --- compat/mingw.c | 18 +++++++++++++++++- date.c | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f5b64fc564..7f5067676c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -81,10 +81,26 @@ int mkstemp (char *__template) return -1; return open(filename, O_RDWR | O_CREAT); } + int gettimeofday(struct timeval *tv, void *tz) { - return -1; + extern time_t my_mktime(struct tm *tm); + SYSTEMTIME st; + struct tm tm; + GetSystemTime(&st); + tm.tm_year = st.wYear-1900; + tm.tm_mon = st.wMonth-1; + tm.tm_mday = st.wDay; + tm.tm_hour = st.wHour; + tm.tm_min = st.wMinute; + tm.tm_sec = st.wSecond; + tv->tv_sec = my_mktime(&tm); + if (tv->tv_sec < 0) + return -1; + tv->tv_usec = st.wMilliseconds*1000; + return 0; } + int pipe(int filedes[2]) { int fd; diff --git a/date.c b/date.c index 542c004c2e..11aa176a7f 100644 --- a/date.c +++ b/date.c @@ -6,7 +6,7 @@ #include "cache.h" -static time_t my_mktime(struct tm *tm) +time_t my_mktime(struct tm *tm) { static const int mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 From 5c098f977167ae604483848323c123c2ae620e6b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 29 Jan 2007 13:46:49 +0100 Subject: [PATCH 0076/3720] Ignore cpio, the cpio emulator. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6da1cdbd0d..8cd125a9d1 100644 --- a/.gitignore +++ b/.gitignore @@ -158,3 +158,4 @@ config.status config.mak.autogen config.mak.append configure +cpio From 3b3ed42c0371b1b99163024ba0dd289b3471a886 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 29 Jan 2007 18:34:37 +0100 Subject: [PATCH 0077/3720] Update README.MinGW: blame works. --- README.MinGW | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.MinGW b/README.MinGW index 0f15eaf92c..3c67064f3f 100644 --- a/README.MinGW +++ b/README.MinGW @@ -51,14 +51,13 @@ This works: - Many porcelains, in particular, checkout, add, rm, commit, diff, branch, merge, rebase, log, show, bisect, grep... - pull, clone, fetch, push via ssh. -- local pull, clone, fetch, push. +- Local pull, clone, fetch, push. - gitk, if invoked as "wish84 \bin\gitk", but there are artefacts in its layout. This does not work: - pull, clone, fetch, push via native GIT protocol. -- blame - daemon, svn, *import, cvs* - and certainly a lot more that I never have found a need to look at. From 3a8b35c3e37369014dc06c767e8fa569150a1e59 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 31 Jan 2007 18:04:12 +0100 Subject: [PATCH 0078/3720] Renaming .gitk-new to .gitk fails if there is already a .gitk. Remove the existing one before renaming. --- gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk b/gitk index 7ef401fb6d..f17ba365eb 100755 --- a/gitk +++ b/gitk @@ -822,6 +822,7 @@ proc savestuff {w} { } puts $f "}" close $f + catch {file delete "~/.gitk"} file rename -force "~/.gitk-new" "~/.gitk" } set stuffsaved 1 From 1973bc88c31030094b8e9191d148dfd2133b431c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 29 Jan 2007 21:53:28 -0800 Subject: [PATCH 0079/3720] Use show-ref instead of ls-remote It used to be ls-remote on self was the only easy way to grab the ref information. Now we have show-ref which does not involve fork and IPC, so use it. Signed-off-by: Junio C Hamano --- gitk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitk b/gitk index 031c829f26..fc86af4dcf 100755 --- a/gitk +++ b/gitk @@ -309,9 +309,9 @@ proc readrefs {} { foreach v {tagids idtags headids idheads otherrefids idotherrefs} { catch {unset $v} } - set refd [open [list | git ls-remote [gitdir]] r] + set refd [open [list | git show-ref] r] while {0 <= [set n [gets $refd line]]} { - if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \ + if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \ match id path]} { continue } From f48ce084de9afc7e0c5225b3fa51f4374b42f2ee Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 Feb 2007 15:41:43 +0100 Subject: [PATCH 0080/3720] MinGW: Make git native protocol work. As it turns out, the things returned by Winsock2's socket() are handles that can be passed to ReadFile()/WriteFile() - almost. The way this works is by wrapping those handles into file descriptors with _open_osfhandle(). But it turns out that the sockets created by the plain socket() function are prepared for "overlapped" I/O, which confuses ReadFile()/WriteFile(). Therefore, a reimplementation is provided that uses WSASocket() to explicitly asks for non-overlapped sockets. Special thanks got to H. Peter Anvin, who provided the necessary clues. --- README.MinGW | 6 +++--- compat/mingw.c | 19 +++++++++++++++++++ connect.c | 16 ++++++++++++++++ git-compat-util.h | 3 +++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/README.MinGW b/README.MinGW index 3c67064f3f..4a454edf2c 100644 --- a/README.MinGW +++ b/README.MinGW @@ -50,14 +50,14 @@ This works: - All the plumbings. - Many porcelains, in particular, checkout, add, rm, commit, diff, branch, merge, rebase, log, show, bisect, grep... -- pull, clone, fetch, push via ssh. +- pull, clone, fetch, push via native git protocal as well as ssh. - Local pull, clone, fetch, push. - gitk, if invoked as "wish84 \bin\gitk", but there are - artefacts in its layout. + artefacts in its layout. A workaround by Mark Levedahl is in + branch 'devel'. This does not work: -- pull, clone, fetch, push via native GIT protocol. - daemon, svn, *import, cvs* - and certainly a lot more that I never have found a need to look at. diff --git a/compat/mingw.c b/compat/mingw.c index 7f5067676c..6887968a10 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,3 +293,22 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) exit(ret); } } + +int mingw_socket(int domain, int type, int protocol) +{ + SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); + if (s == INVALID_SOCKET) { + /* + * WSAGetLastError() values are regular BSD error codes + * biased by WSABASEERR. + * However, strerror() does not know about networking + * specific errors, which are values beginning at 38 or so. + * Therefore, we choose to leave the biased error code + * in errno so that _if_ someone looks up the code somewhere, + * then it is at least the number that are usually listed. + */ + errno = WSAGetLastError(); + return -1; + } + return s; +} diff --git a/connect.c b/connect.c index 3612c5538c..39cc73e9aa 100644 --- a/connect.c +++ b/connect.c @@ -527,7 +527,23 @@ static int git_tcp_connect_sock(char *host) static void git_tcp_connect(int fd[2], char *host) { +#ifndef __MINGW32__ int sockfd = git_tcp_connect_sock(host); +#else + int sockfd; + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2,2), &wsa)) + die("unable to initialize winsock subsystem, error %d", + WSAGetLastError()); + atexit((void(*)(void)) WSACleanup); + + sockfd = git_tcp_connect_sock(host); + /* convert into a file descriptor */ + if ((sockfd = _open_osfhandle(sockfd, O_RDWR|O_BINARY)) < 0) + die("unable to make a socket file descriptor: %s", + strerror(errno)); +#endif fd[0] = sockfd; fd[1] = dup(sockfd); diff --git a/git-compat-util.h b/git-compat-util.h index 37ac8dbc23..cafca04d01 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -374,6 +374,9 @@ struct tm *localtime_r(const time_t *timep, struct tm *result); char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd +int mingw_socket(int domain, int type, int protocol); +#define socket mingw_socket + #define setlinebuf(x) #define fsync(x) From 1ed87d37f22ff90823cd1fd719193a3d9a279cbb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 5 Feb 2007 17:07:42 -0800 Subject: [PATCH 0081/3720] receive-pack.c: fix mismerge. Commit 29d231eb mismerged to introduce style breakage. Signed-off-by: Junio C Hamano --- receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receive-pack.c b/receive-pack.c index c51f417aed..7311c822dd 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -423,7 +423,7 @@ int main(int argc, char **argv) if (!dir) usage(receive_pack_usage); - if(!enter_repo(dir, 0)) + if (!enter_repo(dir, 0)) die("'%s': unable to chdir or not a git archive", dir); if (is_repository_shallow()) From 8101270a3f1ac743b665b0bd93564316f71d1923 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 13 Feb 2007 19:37:40 -0800 Subject: [PATCH 0082/3720] Revert "in_merge_bases(): optimization" This reverts commit dc3806d39698899fe81e55c0daa5bd9d30d13d9c. --- commit.c | 46 +++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/commit.c b/commit.c index bbb9840c48..b37e3dd0ad 100644 --- a/commit.c +++ b/commit.c @@ -1063,7 +1063,7 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *base_traverse(struct commit_list *list, struct commit *stop) +static struct commit_list *base_traverse(struct commit_list *list) { struct commit_list *result = NULL; @@ -1097,20 +1097,10 @@ static struct commit_list *base_traverse(struct commit_list *list, struct commit p->object.flags |= flags; insert_by_date(p, &list); } - if (stop && (stop->object.flags & PARENT2)) { - free_commit_list(list); - list = NULL; - insert_by_date(stop, &list); - return list; - } } /* Clean up the result to remove stale ones */ free_commit_list(list); - - if (stop) - return NULL; - list = result; result = NULL; while (list) { struct commit_list *n = list->next; @@ -1140,7 +1130,7 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two) insert_by_date(one, &list); insert_by_date(two, &list); - return base_traverse(list, NULL); + return base_traverse(list); } struct commit_list *get_merge_bases(struct commit *one, @@ -1205,30 +1195,20 @@ struct commit_list *get_merge_bases(struct commit *one, int in_merge_bases(struct commit *commit, struct commit **reference, int num) { - struct commit_list *result, *list; - int i, ret; + struct commit_list *bases, *b; + int ret = 0; - list = NULL; - parse_commit(commit); - commit->object.flags |= PARENT1; - insert_by_date(commit, &list); - - for (i = 0; i < num; i++) { - struct commit *two = reference[i]; - parse_commit(two); - if (!(two->object.flags & PARENT2)) { - two->object.flags |= PARENT2; - insert_by_date(two, &list); + if (num == 1) + bases = get_merge_bases(commit, *reference, 1); + else + die("not yet"); + for (b = bases; b; b = b->next) { + if (!hashcmp(commit->object.sha1, b->item->object.sha1)) { + ret = 1; + break; } } - result = base_traverse(list, commit); - ret = !!result; - free_commit_list(result); - clear_commit_marks(commit, all_flags); - for (i = 0; i < num; i++) { - struct commit *two = reference[i]; - clear_commit_marks(two, all_flags); - } + free_commit_list(bases); return ret; } From 5e52001ae27ba4c1b3b86864819a5fe895a0c32e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 13 Feb 2007 19:37:46 -0800 Subject: [PATCH 0083/3720] Revert "merge_base(): move traversal into a separate function." This reverts commit 40e0e66bb00646fbdc998c4fe01280470489d0e5. --- commit.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/commit.c b/commit.c index b37e3dd0ad..8d279b0b63 100644 --- a/commit.c +++ b/commit.c @@ -1063,10 +1063,25 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *base_traverse(struct commit_list *list) +static struct commit_list *merge_bases(struct commit *one, struct commit *two) { + struct commit_list *list = NULL; struct commit_list *result = NULL; + if (one == two) + /* We do not mark this even with RESULT so we do not + * have to clean it up. + */ + return commit_list_insert(one, &result); + + parse_commit(one); + parse_commit(two); + + one->object.flags |= PARENT1; + two->object.flags |= PARENT2; + insert_by_date(one, &list); + insert_by_date(two, &list); + while (interesting(list)) { struct commit *commit; struct commit_list *parents; @@ -1112,27 +1127,6 @@ static struct commit_list *base_traverse(struct commit_list *list) return result; } -static struct commit_list *merge_bases(struct commit *one, struct commit *two) -{ - struct commit_list *list = NULL; - - if (one == two) - /* We do not mark this even with RESULT so we do not - * have to clean it up. - */ - return commit_list_insert(one, &list); - - parse_commit(one); - parse_commit(two); - - one->object.flags |= PARENT1; - two->object.flags |= PARENT2; - insert_by_date(one, &list); - insert_by_date(two, &list); - - return base_traverse(list); -} - struct commit_list *get_merge_bases(struct commit *one, struct commit *two, int cleanup) From 079f7cb27b6636f9153c24a82f3d5d74a7b0b6b1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 13 Feb 2007 19:44:24 -0800 Subject: [PATCH 0084/3720] Revert jc/3way topic altogether. Signed-off-by: Junio C Hamano --- git-checkout.sh | 7 ------- git-merge.sh | 47 +---------------------------------------------- 2 files changed, 1 insertion(+), 53 deletions(-) diff --git a/git-checkout.sh b/git-checkout.sh index 3e09f4d92b..14835a4aa9 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -191,9 +191,6 @@ else exit 1 ;; esac - # First stash away the local changes - git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF - # Match the index to the working tree, and do a three-way. git diff-files --name-only | git update-index --remove --stdin && work=`git write-tree` && @@ -218,10 +215,6 @@ else sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" echo "$unmerged" ) | git update-index --index-info - - echo >&2 "Conflicts in locally modified files:" - git diff --name-only --diff-filter=U >&2 - echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF" ;; esac exit 0 diff --git a/git-merge.sh b/git-merge.sh index b0f4c67bf8..04a5eb0f29 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -97,51 +97,6 @@ finish () { esac } -merge_local_changes () { - merge_error=$(git-read-tree -m -u --exclude-per-directory=.gitignore $1 $2 2>&1) || ( - - # First stash away the local changes - git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF - - # Match the index to the working tree, and do a three-way. - git diff-files --name-only | - git update-index --remove --stdin && - work=`git write-tree` && - git read-tree --reset -u $2 && - git read-tree -m -u --aggressive --exclude-per-directory=.gitignore $1 $2 $work || exit - - echo >&2 "Carrying local changes forward." - if result=`git write-tree 2>/dev/null` - then - echo >&2 "Trivially automerged." - else - git merge-index -o git-merge-one-file -a - fi - - # Do not register the cleanly merged paths in the index - # yet; this is not a real merge before committing, but - # just carrying the working tree changes along. - unmerged=`git ls-files -u` - git read-tree --reset $2 - case "$unmerged" in - '') ;; - *) - ( - z40=0000000000000000000000000000000000000000 - echo "$unmerged" | - sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" - echo "$unmerged" - ) | git update-index --index-info - - echo >&2 "Conflicts in locally modified files:" - git diff --name-only --diff-filter=U >&2 - echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF" - ;; - esac - exit 0 - ) -} - merge_name () { remote="$1" rh=$(git-rev-parse --verify "$remote^0" 2>/dev/null) || return @@ -335,7 +290,7 @@ f,*) echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)" git-update-index --refresh 2>/dev/null new_head=$(git-rev-parse --verify "$1^0") && - merge_local_changes $head $new_head && + git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" && finish "$new_head" "Fast forward" dropsave exit 0 From 0bcd515c57e355e02531c5d00d747a54df3e5942 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 11:38:15 +0100 Subject: [PATCH 0085/3720] mkstemp implementation: Specify a umask for open(). We have been lucky in the past that the missing argument was taken from whatever random value was on the stack and it was still a somewhat useful umask, but we should really specify 0600 there. --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6887968a10..70a8e1f78f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -79,7 +79,7 @@ int mkstemp (char *__template) char *filename = mktemp(__template); if (filename == NULL) return -1; - return open(filename, O_RDWR | O_CREAT); + return open(filename, O_RDWR | O_CREAT, 0600); } int gettimeofday(struct timeval *tv, void *tz) From f67787066394b2b348071a8046aad00ef553d3f7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 12:11:54 +0100 Subject: [PATCH 0086/3720] strtoumax is not available on Windows; fall back to strtoul. --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index cafca04d01..761458cef9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -379,6 +379,7 @@ int mingw_socket(int domain, int type, int protocol); #define setlinebuf(x) #define fsync(x) +#define strtoumax strtoul extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From e919589df17960ff9a1ce653032ee0a4876aca06 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 10:50:41 +0100 Subject: [PATCH 0087/3720] Move #include to git-compat-util.h. --- git-compat-util.h | 1 + pager.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 761458cef9..1f2f187284 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -39,6 +39,7 @@ #include //#include //#include +//#include #include #include //#include diff --git a/pager.c b/pager.c index 48b3cb3c17..a63fe31bb5 100644 --- a/pager.c +++ b/pager.c @@ -1,8 +1,6 @@ #include "cache.h" #include "spawn-pipe.h" -#include - /* * This is split up from the rest of git so that we might do * something different on Windows, for example. From b565323c2dd91483496119102dd5e49295c26d31 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 13:13:31 +0100 Subject: [PATCH 0088/3720] Funny characters in file names are not supported on Windows, skip test. --- t/t4016-diff-quote.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index edde8f5568..174ea4b6f1 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -8,6 +8,13 @@ test_description='Quoting paths in diff output. . ./test-lib.sh +if test "$no_symlinks" +then + say 'Filenames with tabs and new-lines not supported, skipping tests.' + test_done + exit +fi + P0='pathname' P1='pathname with HT' P2='pathname with SP' From e62f9693f184d53b27820139ab4f811f41b2ced3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 13:43:18 +0100 Subject: [PATCH 0089/3720] Update README.MinGW. gitk's layout works now well with the upstream version. --- README.MinGW | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.MinGW b/README.MinGW index 4a454edf2c..c6c059e24d 100644 --- a/README.MinGW +++ b/README.MinGW @@ -30,7 +30,7 @@ In order to compile this code you need: compile this into regex.o, ar it into libregex.a and install it in /mingw/lib, include file into /mingw/include - tcltk-8.4.1-1.exe (for gitk, but it's untested so far) + tcltk-8.4.1-1.exe (for gitk, git-gui) It is absolutely necessary that you install MSYS in a path that does not contain special characters, like spaces. I have it in @@ -52,9 +52,7 @@ This works: branch, merge, rebase, log, show, bisect, grep... - pull, clone, fetch, push via native git protocal as well as ssh. - Local pull, clone, fetch, push. -- gitk, if invoked as "wish84 \bin\gitk", but there are - artefacts in its layout. A workaround by Mark Levedahl is in - branch 'devel'. +- gitk, if invoked as "wish84 \bin\gitk". Ditto for git-gui. This does not work: From e0dd8fcfe3055d3874c2351cb6c227200b49ee1b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 09:57:47 +0100 Subject: [PATCH 0090/3720] Revert "Funny characters in file names are not supported on Windows, skip test." This reverts commit b565323c2dd91483496119102dd5e49295c26d31. A better, generic solution is now in upstream. --- t/t4016-diff-quote.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index a203653b76..2e7cd5f255 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -8,13 +8,6 @@ test_description='Quoting paths in diff output. . ./test-lib.sh -if test "$no_symlinks" -then - say 'Filenames with tabs and new-lines not supported, skipping tests.' - test_done - exit -fi - P0='pathname' P1='pathname with HT' P2='pathname with SP' From dfa7eac0c0a6fac5e55c5ee77c4410630b07872f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 09:58:40 +0100 Subject: [PATCH 0091/3720] Use compat/strtoumax.c as a substitute for the missing strtoumax. This reverts commit f67787066394b2b348071a8046aad00ef553d3f7 and uses the compatibility facilities that upstream includes. --- Makefile | 1 + git-compat-util.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index afe4cd8d1b..95b92a3597 100644 --- a/Makefile +++ b/Makefile @@ -437,6 +437,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRLCPY=YesPlease NO_ICONV=YesPlease NO_C99_FORMAT = YesPlease + NO_STRTOUMAX = YesPlease NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat diff --git a/git-compat-util.h b/git-compat-util.h index 74f8317467..a8df17ae43 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -395,7 +395,6 @@ int mingw_socket(int domain, int type, int protocol); #define setlinebuf(x) #define fsync(x) -#define strtoumax strtoul extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From fba729381275254038c1e5a301b10e2b103d727d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 10:38:16 +0100 Subject: [PATCH 0092/3720] Flush stdout before closing it. This embarrassing omission was the reason that only incomplete data was sent to the automatically invoked pager. --- README.MinGW | 6 ------ pager.c | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/README.MinGW b/README.MinGW index c6c059e24d..a8ad34bc4b 100644 --- a/README.MinGW +++ b/README.MinGW @@ -61,12 +61,6 @@ This does not work: Caveats (aka bugs): -- The automatic pager of commands like log or diff does not work - correctly: It does not display some portion of text at the end. - That is, if what you should see is less than 4K, you see nothing at - all; otherwise something up to 4K at the end is missing. Use - `git log | less' in these cases. Or `set PAGER=cat' (which is - optimized to skip the pager entirely). - Internally, the ported tools must do their own command line quoting when other plumbings are executed. This sort of quoting is currently implemented *very* simplistic: It just watches out for whitespace diff --git a/pager.c b/pager.c index a63fe31bb5..f4f999ef6e 100644 --- a/pager.c +++ b/pager.c @@ -26,6 +26,7 @@ static void run_pager(const char *pager) static pid_t pager_pid; static void collect_pager(void) { + fflush(stdout); close(1); /* signals EOF to pager */ cwait(NULL, pager_pid, 0); } From 3077c83763853b703f52c1279e6d5a7e7e179599 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 11:38:16 +0100 Subject: [PATCH 0093/3720] Really run scripts under the interpreter specified in the first line. Earlier we would have run all scripts under 'sh', but only changed the name (argv[0]) to the parsed interpreter. While we are here, also ignore command line options specified in the interpreter line; perl's -w is the common case. --- compat/mingw.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 70a8e1f78f..dbc13f0c8a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -230,7 +230,7 @@ void quote_argv(const char **dst, const char **src) const char *parse_interpreter(const char *cmd) { static char buf[100]; - char *p; + char *p, *opt; int n, fd; /* don't even try a .exe */ @@ -256,6 +256,9 @@ const char *parse_interpreter(const char *cmd) *p = '\0'; if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\'))) return NULL; + /* strip options */ + if ((opt = strchr(p+1, ' '))) + *opt = '\0'; return p+1; } @@ -278,7 +281,7 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) sh_argv[0] = interpr; sh_argv[1] = cmd; quote_argv(&sh_argv[2], &argv[1]); - n = spawnvpe(_P_WAIT, "sh", sh_argv, env); + n = spawnvpe(_P_WAIT, interpr, sh_argv, env); if (n == -1) return 1; /* indicate that we tried but failed */ exit(n); From bd2f73a6ba6daf6158112874414d338c7b0e528d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 11:44:19 +0100 Subject: [PATCH 0094/3720] Support the tools scripted in perl. There is one subtlety in perl/Makefile: The $(prefix) may contain a drive letter-colon combination. But unfortunately, the perl scripts contain a stance that splits the path at colons to find Git.pm. For this reason, we convert the path to the MSYS style, which does not have the colon. --- Makefile | 2 ++ perl/Makefile | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 95b92a3597..cb32c2f2e7 100644 --- a/Makefile +++ b/Makefile @@ -424,6 +424,7 @@ ifeq ($(uname_S),IRIX64) endif ifneq (,$(findstring MINGW,$(uname_S))) SHELL_PATH = $(shell cd /bin && pwd -W)/sh + PERL_PATH = $(shell cd /bin && pwd -W)/perl NO_MMAP=YesPlease NO_PREAD=YesPlease NO_OPENSSL=YesPlease @@ -440,6 +441,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRTOUMAX = YesPlease NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease + NO_PERL_MAKEMAKER=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o EXTLIBS += -lws2_32 -lregex diff --git a/perl/Makefile b/perl/Makefile index 099beda873..fdb7cb9886 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -16,7 +16,11 @@ clean: $(RM) $(makfile).old ifdef NO_PERL_MAKEMAKER -instdir_SQ = $(subst ','\'',$(prefix)/lib) +# We exploit that /bin/sh transforms the DOS-Stype path in TEMP into +# the MSYS style pseudo-mount form. +# This colon-free from is needed because our perl scripts look at +# $(instdir_SQ) and split it at colons. +instdir_SQ = $(subst ','\'',$(shell cmd /x/d/c "set TEMP=$(prefix)/lib && sh -c 'echo \$$TEMP'")) $(makfile): ../GIT-CFLAGS Makefile echo all: > $@ echo ' :' >> $@ From e5805d2c579f9040d0381b046313e9ef0f189711 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 1 Mar 2007 10:40:57 +0100 Subject: [PATCH 0095/3720] Use /tmp instead of /var/tmp. --- git-gui/CREDITS-GEN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/CREDITS-GEN b/git-gui/CREDITS-GEN index d1b0f86355..1aff2f8088 100755 --- a/git-gui/CREDITS-GEN +++ b/git-gui/CREDITS-GEN @@ -36,7 +36,7 @@ generate_credits () # that fact. # -credits_tmp=/var/tmp/gitgui-credits-$$ +credits_tmp=/tmp/gitgui-credits-$$ trap 'rm -f "$credits_tmp"' 0 orig="$credits_tmp" From 02560cdbcffb497304513b84f14b4bf5a0ec8a9c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 1 Mar 2007 22:09:05 +0100 Subject: [PATCH 0096/3720] Include regex.[ch] in compat/ They are both GPLed, so there is no problem with it. Signed-off-by: Johannes Schindelin --- Makefile | 4 +- compat/regex.c | 4921 ++++++++++++++++++++++++++++++++++++++++++++++++ compat/regex.h | 490 +++++ 3 files changed, 5413 insertions(+), 2 deletions(-) create mode 100644 compat/regex.c create mode 100644 compat/regex.h diff --git a/Makefile b/Makefile index cb32c2f2e7..92151f25d4 100644 --- a/Makefile +++ b/Makefile @@ -443,8 +443,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o - EXTLIBS += -lws2_32 -lregex + COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o + EXTLIBS += -lws2_32 X = .exe NOEXECTEMPL = .noexec endif diff --git a/compat/regex.c b/compat/regex.c new file mode 100644 index 0000000000..2d57c70b9c --- /dev/null +++ b/compat/regex.c @@ -0,0 +1,4921 @@ +/* Extended regular expression matching and search library, + version 0.12. + (Implements POSIX draft P10003.2/D11.2, except for + internationalization features.) + + Copyright (C) 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (REGEX_MALLOC) + #pragma alloca +#endif + +#define _GNU_SOURCE + +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +#include + +/* We used to test for `BSTRING' here, but only GCC and Emacs define + `BSTRING', as far as I know, and neither of them use this code. */ +#include +#ifndef bcmp +#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) +#endif +#ifndef bcopy +#define bcopy(s, d, n) memcpy ((d), (s), (n)) +#endif +#ifndef bzero +#define bzero(s, n) memset ((s), 0, (n)) +#endif + +#include + + +/* Define the syntax stuff for \<, \>, etc. */ + +/* This must be nonzero for the wordchar and notwordchar pattern + commands in re_match_2. */ +#ifndef Sword +#define Sword 1 +#endif + +#ifdef SYNTAX_TABLE + +extern char *re_syntax_table; + +#else /* not SYNTAX_TABLE */ + +/* How many characters in the character set. */ +#define CHAR_SET_SIZE 256 + +static char re_syntax_table[CHAR_SET_SIZE]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + re_syntax_table['_'] = Sword; + + done = 1; +} + +#endif /* not SYNTAX_TABLE */ + +#define SYNTAX(c) re_syntax_table[c] + + +/* Get the interface, including the syntax bits. */ +#include "regex.h" + +/* isalpha etc. are used for the character classes. */ +#include + +#ifndef isascii +#define isascii(c) 1 +#endif + +#ifdef isblank +#define ISBLANK(c) (isascii (c) && isblank (c)) +#else +#define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +#define ISGRAPH(c) (isascii (c) && isgraph (c)) +#else +#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c)) +#endif + +#define ISPRINT(c) (isascii (c) && isprint (c)) +#define ISDIGIT(c) (isascii (c) && isdigit (c)) +#define ISALNUM(c) (isascii (c) && isalnum (c)) +#define ISALPHA(c) (isascii (c) && isalpha (c)) +#define ISCNTRL(c) (isascii (c) && iscntrl (c)) +#define ISLOWER(c) (isascii (c) && islower (c)) +#define ISPUNCT(c) (isascii (c) && ispunct (c)) +#define ISSPACE(c) (isascii (c) && isspace (c)) +#define ISUPPER(c) (isascii (c) && isupper (c)) +#define ISXDIGIT(c) (isascii (c) && isxdigit (c)) + +#ifndef NULL +#define NULL 0 +#endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +#define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +#ifdef REGEX_MALLOC + +#define REGEX_ALLOCATE malloc +#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) + +#else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +#ifndef alloca + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if HAVE_ALLOCA_H +#include +#else /* not __GNUC__ or HAVE_ALLOCA_H */ +#ifndef _AIX /* Already did AIX, up at the top. */ +char *alloca (); +#endif /* not _AIX */ +#endif /* not HAVE_ALLOCA_H */ +#endif /* not __GNUC__ */ + +#endif /* not alloca */ + +#define REGEX_ALLOCATE alloca + +/* Assumes a `char *destination' variable. */ +#define REGEX_REALLOCATE(source, osize, nsize) \ + (destination = (char *) alloca (nsize), \ + bcopy (source, destination, osize), \ + destination) + +#endif /* not REGEX_MALLOC */ + + +/* True if `size1' is non-NULL and PTR is pointing anywhere inside + `string1' or just past its end. This works if PTR is NULL, which is + a good thing. */ +#define FIRST_STRING_P(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* (Re)Allocate N items of type T using malloc, or fail. */ +#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) +#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + +#define BYTEWIDTH 8 /* In bits. */ + +#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +typedef char boolean; +#define false 0 +#define true 1 + +/* These are the command codes that appear in compiled regular + expressions. Some opcodes are followed by argument bytes. A + command code can specify any interpretation whatsoever for its + arguments. Zero bytes may appear in the compiled regular expression. + + The value of `exactn' is needed in search.c (search_buffer) in Emacs. + So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of + `exactn' we use here must also be 1. */ + +typedef enum +{ + no_op = 0, + + /* Followed by one byte giving n, then by n literal bytes. */ + exactn = 1, + + /* Matches any (more or less) character. */ + anychar, + + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ + charset, + + /* Same parameters as charset, but match any character that is + not one of those specified. */ + charset_not, + + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ + start_memory, + + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ + stop_memory, + + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ + duplicate, + + /* Fail unless at beginning of line. */ + begline, + + /* Fail unless at end of line. */ + endline, + + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ + begbuf, + + /* Analogously, for end of buffer/string. */ + endbuf, + + /* Followed by two byte relative address to which to jump. */ + jump, + + /* Same as jump, but marks the end of an alternative. */ + jump_past_alt, + + /* Followed by two-byte relative address of place to resume at + in case of failure. */ + on_failure_jump, + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ + on_failure_keep_string_jump, + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ + pop_failure_jump, + + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ + maybe_pop_jump, + + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ + dummy_failure_jump, + + /* Push a dummy failure point and continue. Used at the end of + alternatives. */ + push_dummy_failure, + + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ + succeed_n, + + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ + jump_n, + + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ + set_number_at, + + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + + wordbound, /* Succeeds if at a word boundary. */ + notwordbound /* Succeeds if not at a word boundary. */ + +#ifdef emacs + ,before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + + /* Matches any character whose syntax is specified. Followed by + a byte which contains a syntax code, e.g., Sword. */ + syntaxspec, + + /* Matches any character whose syntax is not that specified. */ + notsyntaxspec +#endif /* emacs */ +} re_opcode_t; + +/* Common operations on the compiled pattern. */ + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ + +#define STORE_NUMBER(destination, number) \ + do { \ + (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; \ + } while (0) + +/* Same as STORE_NUMBER, except increment DESTINATION to + the byte after where the number is stored. Therefore, DESTINATION + must be an lvalue. */ + +#define STORE_NUMBER_AND_INCR(destination, number) \ + do { \ + STORE_NUMBER (destination, number); \ + (destination) += 2; \ + } while (0) + +/* Put into DESTINATION a number stored in two contiguous bytes starting + at SOURCE. */ + +#define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ + } while (0) + +#ifdef DEBUG +static void +extract_number (dest, source) + int *dest; + unsigned char *source; +{ + int temp = SIGN_EXTEND_CHAR (*(source + 1)); + *dest = *source & 0377; + *dest += temp << 8; +} + +#ifndef EXTRACT_MACROS /* To debug the macros. */ +#undef EXTRACT_NUMBER +#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) +#endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. + SOURCE must be an lvalue. */ + +#define EXTRACT_NUMBER_AND_INCR(destination, source) \ + do { \ + EXTRACT_NUMBER (destination, source); \ + (source) += 2; \ + } while (0) + +#ifdef DEBUG +static void +extract_number_and_incr (destination, source) + int *destination; + unsigned char **source; +{ + extract_number (destination, *source); + *source += 2; +} + +#ifndef EXTRACT_MACROS +#undef EXTRACT_NUMBER_AND_INCR +#define EXTRACT_NUMBER_AND_INCR(dest, src) \ + extract_number_and_incr (&dest, &src) +#endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* If DEBUG is defined, Regex prints many voluminous messages about what + it is doing (if the variable `debug' is nonzero). If linked with the + main program in `iregex.c', you can enter patterns and strings + interactively. And if linked with the main program in `main.c' and + the other test files, you can run the already-written tests. */ + +#ifdef DEBUG + +/* We use standard I/O for debugging. */ +#include + +/* It is useful to test things that ``must'' be true when debugging. */ +#include + +static int debug = 0; + +#define DEBUG_STATEMENT(e) e +#define DEBUG_PRINT1(x) if (debug) printf (x) +#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) +#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) +#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) +#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug) print_partial_compiled_pattern (s, e) +#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug) print_double_string (w, s1, sz1, s2, sz2) + + +extern void printchar (); + +/* Print the fastmap in human-readable form. */ + +void +print_fastmap (fastmap) + char *fastmap; +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + printchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + printchar (i - 1); + } + } + } + putchar ('\n'); +} + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +print_partial_compiled_pattern (start, end) + unsigned char *start; + unsigned char *end; +{ + int mcnt, mcnt2; + unsigned char *p = start; + unsigned char *pend = end; + + if (start == NULL) + { + printf ("(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { + switch ((re_opcode_t) *p++) + { + case no_op: + printf ("/no_op"); + break; + + case exactn: + mcnt = *p++; + printf ("/exactn/%d", mcnt); + do + { + putchar ('/'); + printchar (*p++); + } + while (--mcnt); + break; + + case start_memory: + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; + + case stop_memory: + mcnt = *p++; + printf ("/stop_memory/%d/%d", mcnt, *p++); + break; + + case duplicate: + printf ("/duplicate/%d", *p++); + break; + + case anychar: + printf ("/anychar"); + break; + + case charset: + case charset_not: + { + register int c; + + printf ("/charset%s", + (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); + + assert (p + *p < pend); + + for (c = 0; c < *p; c++) + { + unsigned bit; + unsigned char map_byte = p[1 + c]; + + putchar ('/'); + + for (bit = 0; bit < BYTEWIDTH; bit++) + if (map_byte & (1 << bit)) + printchar (c * BYTEWIDTH + bit); + } + p += 1 + *p; + break; + } + + case begline: + printf ("/begline"); + break; + + case endline: + printf ("/endline"); + break; + + case on_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_jump/0/%d", mcnt); + break; + + case on_failure_keep_string_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_keep_string_jump/0/%d", mcnt); + break; + + case dummy_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/dummy_failure_jump/0/%d", mcnt); + break; + + case push_dummy_failure: + printf ("/push_dummy_failure"); + break; + + case maybe_pop_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/maybe_pop_jump/0/%d", mcnt); + break; + + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/pop_failure_jump/0/%d", mcnt); + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); + printf ("/jump_past_alt/0/%d", mcnt); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + printf ("/jump/0/%d", mcnt); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); + break; + + case wordbound: + printf ("/wordbound"); + break; + + case notwordbound: + printf ("/notwordbound"); + break; + + case wordbeg: + printf ("/wordbeg"); + break; + + case wordend: + printf ("/wordend"); + +#ifdef emacs + case before_dot: + printf ("/before_dot"); + break; + + case at_dot: + printf ("/at_dot"); + break; + + case after_dot: + printf ("/after_dot"); + break; + + case syntaxspec: + printf ("/syntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; + + case notsyntaxspec: + printf ("/notsyntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; +#endif /* emacs */ + + case wordchar: + printf ("/wordchar"); + break; + + case notwordchar: + printf ("/notwordchar"); + break; + + case begbuf: + printf ("/begbuf"); + break; + + case endbuf: + printf ("/endbuf"); + break; + + default: + printf ("?%d", *(p-1)); + } + } + printf ("/\n"); +} + + +void +print_compiled_pattern (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *buffer = bufp->buffer; + + print_partial_compiled_pattern (buffer, buffer + bufp->used); + printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + + printf ("re_nsub: %d\t", bufp->re_nsub); + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("newline_anchor: %d\n", bufp->newline_anchor); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %d\n", bufp->syntax); + /* Perhaps we should print the translate table? */ +} + + +void +print_double_string (where, string1, size1, string2, size2) + const char *where; + const char *string1; + const char *string2; + int size1; + int size2; +{ + unsigned this_char; + + if (where == NULL) + printf ("(null)"); + else + { + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + printchar (string1[this_char]); + + where = string2; + } + + for (this_char = where - string2; this_char < size2; this_char++) + printchar (string2[this_char]); + } +} + +#else /* not DEBUG */ + +#undef assert +#define assert(e) + +#define DEBUG_STATEMENT(e) +#define DEBUG_PRINT1(x) +#define DEBUG_PRINT2(x1, x2) +#define DEBUG_PRINT3(x1, x2, x3) +#define DEBUG_PRINT4(x1, x2, x3, x4) +#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +#endif /* not DEBUG */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; + return ret; +} + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. */ + +static const char *re_error_msg[] = + { NULL, /* REG_NOERROR */ + "No match", /* REG_NOMATCH */ + "Invalid regular expression", /* REG_BADPAT */ + "Invalid collation character", /* REG_ECOLLATE */ + "Invalid character class name", /* REG_ECTYPE */ + "Trailing backslash", /* REG_EESCAPE */ + "Invalid back reference", /* REG_ESUBREG */ + "Unmatched [ or [^", /* REG_EBRACK */ + "Unmatched ( or \\(", /* REG_EPAREN */ + "Unmatched \\{", /* REG_EBRACE */ + "Invalid content of \\{\\}", /* REG_BADBR */ + "Invalid range end", /* REG_ERANGE */ + "Memory exhausted", /* REG_ESPACE */ + "Invalid preceding regular expression", /* REG_BADRPT */ + "Premature end of regular expression", /* REG_EEND */ + "Regular expression too big", /* REG_ESIZE */ + "Unmatched ) or \\)", /* REG_ERPAREN */ + }; + +/* Subroutine declarations and macros for regex_compile. */ + +static void store_op1 (), store_op2 (); +static void insert_op1 (), insert_op2 (); +static boolean at_begline_loc_p (), at_endline_loc_p (); +static boolean group_in_compile_stack (); +static reg_errcode_t compile_range (); + +/* Fetch the next character in the uncompiled pattern---translating it + if necessary. Also cast from a signed character in the constant + string passed to us by the user to an unsigned char that we can use + as an array index (in, e.g., `translate'). */ +#define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + if (translate) c = translate[c]; \ + } while (0) + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + } while (0) + +/* Go backwards one character in the pattern. */ +#define PATUNFETCH p-- + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d)) + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 32 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + while (b - bufp->buffer + (n) > bufp->allocated) \ + EXTEND_BUFFER () + +/* Make sure we have one more byte of buffer space and then add C to it. */ +#define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (unsigned char) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +#define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +#define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + *b++ = (unsigned char) (c3); \ + } while (0) + + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +#define STORE_JUMP(op, loc, to) \ + store_op1 (op, loc, (to) - (loc) - 3) + +/* Likewise, for a two-argument jump. */ +#define STORE_JUMP2(op, loc, to, arg) \ + store_op2 (op, loc, (to) - (loc) - 3, arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP(op, loc, to) \ + insert_op1 (op, loc, (to) - (loc) - 3, b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP2(op, loc, to, arg) \ + insert_op2 (op, loc, (to) - (loc) - 3, arg, b) + + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +#define MAX_BUF_SIZE (1L << 16) + + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#define EXTEND_BUFFER() \ + do { \ + unsigned char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\ + if (bufp->buffer == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } \ + } while (0) + + +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +#define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef unsigned regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +typedef int pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t inner_group_offset; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +#define INIT_COMPILE_STACK_SIZE 32 + +#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + + +/* Set the bit for character C in a list. */ +#define SET_LIST_BIT(c) \ + (b[((unsigned char) (c)) / BYTEWIDTH] \ + |= 1 << (((unsigned char) c) % BYTEWIDTH)) + + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while (ISDIGIT (c)) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +#define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' and `newline_anchor' fields are neither + examined nor set. */ + +static reg_errcode_t +regex_compile (pattern, size, syntax, bufp) + const char *pattern; + int size; + reg_syntax_t syntax; + struct re_pattern_buffer *bufp; +{ + /* We fetch characters from PATTERN here. Even though PATTERN is + `char *' (i.e., signed), we declare these variables as unsigned, so + they can be reliably used as array indices. */ + register unsigned char c, c1; + + /* A random tempory spot in PATTERN. */ + const char *p1; + + /* Points to the end of the buffer, where we should append. */ + register unsigned char *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ + const char *p = pattern; + const char *pend = pattern + size; + + /* How to translate the characters in the pattern. */ + char *translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + unsigned char *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + unsigned char *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + unsigned char *begalt; + + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + const char *beg_interval; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + unsigned char *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + +#ifdef DEBUG + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + printchar (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + return REG_ESPACE; + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined (emacs) && !defined (SYNTAX_TABLE) + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } + if (!bufp->buffer) return REG_ESPACE; + + bufp->allocated = INIT_BUF_SIZE; + } + + begalt = b = bufp->buffer; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; + + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + + if (p == pend) + break; + + PATFETCH (c); + + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; + + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) return REG_EESCAPE; + + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + + c = c1; + } + else + { + PATUNFETCH; + break; + } + + /* If we get here, we found another repeat character. */ + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). + + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); + + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + && zero_times_ok + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); + + /* We've added more stuff to the buffer. */ + b += 3; + } + + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; + + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + boolean had_char_class = false; + + if (p == pend) return REG_EBRACK; + + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) return REG_EBRACK; + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) return REG_EESCAPE; + + PATFETCH (c1); + SET_LIST_BIT (c1); + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + return REG_ERANGE; + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } + + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + + ret = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } + + /* See if we're at the beginning of a possible character + class. */ + + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) return REG_EBRACK; + + for (;;) + { + PATFETCH (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and:`]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) return REG_EBRACK; + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch)) + || (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch)) + || (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) return REG_EESCAPE; + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + bufp->re_nsub++; + regnum++; + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; + + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + break; + + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + return REG_ERPAREN; + + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + return REG_ERPAREN; + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + || (p - 2 == pattern && p == pend)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; + + beg_interval = p - 1; + + if (p == pend) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_EBRACE; + } + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') return REG_EBRACE; + + PATFETCH (c); + } + + if (c != '}') + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } + + /* We just parsed a valid interval. */ + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; + + GET_BUFFER_SPACE (nbytes); + + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; + + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; +#endif /* emacs */ + + + case 'w': + laststart = b; + BUF_PUSH (wordchar); + break; + + + case 'W': + laststart = b; + BUF_PUSH (notwordchar); + break; + + + case '<': + BUF_PUSH (wordbeg); + break; + + case '>': + BUF_PUSH (wordend); + break; + + case 'b': + BUF_PUSH (wordbound); + break; + + case 'B': + BUF_PUSH (notwordbound); + break; + + case '`': + BUF_PUSH (begbuf); + break; + + case '\'': + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; + + c1 = c - '0'; + + if (c1 > regnum) + return REG_ESUBREG; + + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, c1)) + goto normal_char; + + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact == (1 << BYTEWIDTH) - 1 + + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' + || ((syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + /* Start building a new exactn. */ + + laststart = b; + + BUF_PUSH_2 (exactn, 0); + pending_exact = b - 1; + } + + BUF_PUSH (c); + (*pending_exact)++; + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + if (!COMPILE_STACK_EMPTY) + return REG_EPAREN; + + free (compile_stack.stack); + + /* We have succeeded; set the length of the buffer. */ + bufp->used = b - bufp->buffer; + +#ifdef DEBUG + if (debug) + { + DEBUG_PRINT1 ("\nCompiled pattern: "); + print_compiled_pattern (bufp); + } +#endif /* DEBUG */ + + return REG_NOERROR; +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ + +static void +store_op1 (op, loc, arg) + re_opcode_t op; + unsigned char *loc; + int arg; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +store_op2 (op, loc, arg1, arg2) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 3, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ + +static void +insert_op1 (op, loc, arg, end) + re_opcode_t op; + unsigned char *loc; + int arg; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 3; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op1 (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +insert_op2 (op, loc, arg1, arg2, end) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 5; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op2 (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +at_begline_loc_p (pattern, p, syntax) + const char *pattern, *p; + reg_syntax_t syntax; +{ + const char *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +at_endline_loc_p (p, pend, syntax) + const char *p, *pend; + int syntax; +{ + const char *next = p; + boolean next_backslash = *next == '\\'; + const char *next_next = p + 1 < pend ? p + 1 : NULL; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack, regnum) + compile_stack_type compile_stack; + regnum_t regnum; +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} + + +/* Read the ending character of a range (in a bracket expression) from the + uncompiled pattern *P_PTR (which ends at PEND). We assume the + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) + Then we set the translation of all bits between the starting and + ending characters (inclusive) in the compiled pattern B. + + Return an error code. + + We use these short variable names so we can use the same macros as + `regex_compile' itself. */ + +static reg_errcode_t +compile_range (p_ptr, pend, translate, syntax, b) + const char **p_ptr, *pend; + char *translate; + reg_syntax_t syntax; + unsigned char *b; +{ + unsigned this_char; + + const char *p = *p_ptr; + int range_start, range_end; + + if (p == pend) + return REG_ERANGE; + + /* Even though the pattern is a signed `char *', we need to fetch + with unsigned char *'s; if the high bit of the pattern character + is set, the range endpoints will be negative if we fetch using a + signed char *. + + We also want to fetch the endpoints without translating them; the + appropriate translation is done in the bit-setting loop below. */ + range_start = ((unsigned char *) p)[-2]; + range_end = ((unsigned char *) p)[0]; + + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + /* If the start is after the end, the range is empty. */ + if (range_start > range_end) + return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; + + /* Here we see why `this_char' has to be larger than an `unsigned + char' -- the range is inclusive, so if `range_end' == 0xff + (assuming 8-bit characters), we would otherwise go into an infinite + loop, since all characters <= 0xff. */ + for (this_char = range_start; this_char <= range_end; this_char++) + { + SET_LIST_BIT (TRANSLATE (this_char)); + } + + return REG_NOERROR; +} + +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE. */ + + +/* Number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +#ifndef INIT_FAILURE_ALLOC +#define INIT_FAILURE_ALLOC 5 +#endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used MAX_FAILURE_SPACE each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. */ +int re_max_failures = 2000; + +typedef const unsigned char *fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} fail_stack_type; + +#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) +#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) +#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) +#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail]) + + +/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */ + +#define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (fail_stack_elt_t *) \ + REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + } while (0) + + +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE requires `destination' be declared. */ + +#define DOUBLE_FAIL_STACK(fail_stack) \ + ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \ + ? 0 \ + : ((fail_stack).stack = (fail_stack_elt_t *) \ + REGEX_REALLOCATE ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size <<= 1, \ + 1))) + + +/* Push PATTERN_OP on FAIL_STACK. + + Return 1 if was able to do so and 0 if ran out of memory allocating + space to do so. */ +#define PUSH_PATTERN_OP(pattern_op, fail_stack) \ + ((FAIL_STACK_FULL () \ + && !DOUBLE_FAIL_STACK (fail_stack)) \ + ? 0 \ + : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \ + 1)) + +/* This pushes an item onto the failure stack. Must be a four-byte + value. Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_ITEM(item) \ + fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item + +/* The complement operation. Assumes `fail_stack' is nonempty. */ +#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail] + +/* Used to omit pushing failure point id's when we're not debugging. */ +#ifdef DEBUG +#define DEBUG_PUSH PUSH_FAILURE_ITEM +#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM () +#else +#define DEBUG_PUSH(item) +#define DEBUG_POP(item_addr) +#endif + + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend, reg_info, and + num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be + declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ + do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + int this_reg; \ + \ + DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \ + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ + \ + /* Ensure we have enough space allocated for what we will push. */ \ + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ + { \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ + \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + (fail_stack).size); \ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + } \ + \ + /* Push the info, starting with the registers. */ \ + DEBUG_PRINT1 ("\n"); \ + \ + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ + this_reg++) \ + { \ + DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \ + DEBUG_STATEMENT (num_regs_pushed++); \ + \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + PUSH_FAILURE_ITEM (regstart[this_reg]); \ + \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + PUSH_FAILURE_ITEM (regend[this_reg]); \ + \ + DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT1 ("\n"); \ + PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ + } \ + \ + DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\ + PUSH_FAILURE_ITEM (lowest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\ + PUSH_FAILURE_ITEM (highest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ + PUSH_FAILURE_ITEM (pattern_place); \ + \ + DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ + size2); \ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_ITEM (string_place); \ + \ + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ + DEBUG_PUSH (failure_id); \ + } while (0) + +/* This is the number of items that are pushed and popped on the stack + for each register. */ +#define NUM_REG_ITEMS 3 + +/* Individual items aside from the registers. */ +#ifdef DEBUG +#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ +#else +#define NUM_NONREG_ITEMS 4 +#endif + +/* We push at most this many items on the stack. */ +#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS) + +/* We actually push this many items. */ +#define NUM_FAILURE_ITEMS \ + ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \ + + NUM_NONREG_ITEMS) + +/* How many items can still be added to the stack without overflowing it. */ +#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + +#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ +{ \ + DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \ + int this_reg; \ + const unsigned char *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_ITEM (); \ + if (string_temp != NULL) \ + str = (const char *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string 0x%x: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (unsigned char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \ + \ + low_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \ + \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \ + \ + regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + } \ + \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} /* POP_FAILURE_POINT */ + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + int j, k; + fail_stack_type fail_stack; +#ifndef REGEX_MALLOC + char *destination; +#endif + /* We don't push any register information onto the failure stack. */ + unsigned num_regs = 0; + + register char *fastmap = bufp->fastmap; + unsigned char *pattern = bufp->buffer; + unsigned long size = bufp->used; + const unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + + /* Assume that each path through the pattern can be null until + proven otherwise. We set this false at the bottom of switch + statement, to which we get only if a particular path doesn't + match the empty string. */ + boolean path_can_be_null = true; + + /* We aren't doing a `succeed_n' to begin with. */ + boolean succeed_n_p = false; + + assert (fastmap != NULL && p != NULL); + + INIT_FAIL_STACK (); + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + bufp->can_be_null = 0; + + while (p != pend || !FAIL_STACK_EMPTY ()) + { + if (p == pend) + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail]; + } + + /* We should never be about to go beyond the end of the pattern. */ + assert (p < pend); + +#ifdef SWITCH_ENUM_BUG + switch ((int) ((re_opcode_t) *p++)) +#else + switch ((re_opcode_t) *p++) +#endif + { + + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ + case duplicate: + bufp->can_be_null = 1; + return 0; + + + /* Following are the cases which match a character. These end + with `break'. */ + + case exactn: + fastmap[p[1]] = 1; + break; + + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + fastmap[j] = 1; + break; + + + case charset_not: + /* Chars beyond end of map must be allowed. */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 1; + break; + + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + + + case anychar: + /* `.' matches anything ... */ + for (j = 0; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = 0; + + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ + else if (bufp->can_be_null) + return 0; + + /* Otherwise, have to check alternative paths. */ + break; + + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + /* All cases after this match the empty string. These end with + `continue'. */ + + + case before_dot: + case at_dot: + case after_dot: + continue; +#endif /* not emacs */ + + + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + case push_dummy_failure: + continue; + + + case jump_n: + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case jump_past_alt: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump + && (re_opcode_t) *p != succeed_n) + continue; + + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () + && fail_stack.stack[fail_stack.avail - 1] == p) + fail_stack.avail--; + + continue; + + + case on_failure_jump: + case on_failure_keep_string_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + return -2; + } + else + bufp->can_be_null = 1; + + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; + } + + continue; + + + case succeed_n: + /* Get to the number of times to succeed. */ + p += 2; + + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; + + + case set_number_at: + p += 4; + continue; + + + case start_memory: + case stop_memory: + p += 2; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ + path_can_be_null = false; + p = pend; + } /* while p */ + + /* Set `can_be_null' for the last path (also the first path, if the + pattern is empty). */ + bufp->can_be_null |= path_can_be_null; + return 0; +} /* re_compile_fastmap */ + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + unsigned num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t) 0; + } +} + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (bufp, string, size, startpos, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} + + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int startpos; + int range; + struct re_registers *regs; + int stop; +{ + int val; + register char *fastmap = bufp->fastmap; + register char *translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. */ + if (endpos < -1) + range = -1 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern that must be anchored. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + if (range > 0) /* Searching forwards. */ + { + register const char *d; + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (translate) + while (range > lim + && !fastmap[(unsigned char) + translate[(unsigned char) *d++]]) + range--; + else + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; + + startpos += irange - range; + } + else /* Searching backwards. */ + { + register char c = (size1 == 0 || startpos >= size1 + ? string2[startpos - size1] + : string1[startpos]); + + if (!fastmap[(unsigned char) TRANSLATE (c)]) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + return -1; + + val = re_match_2 (bufp, string1, size1, string2, size2, + startpos, regs, stop); + if (val >= 0) + return startpos; + + if (val == -2) + return -2; + + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } + return -1; +} /* re_search_2 */ + +/* Declarations and macros for re_match_2. */ + +static int bcmp_translate (); +static boolean alt_match_null_string_p (), + common_op_match_null_string_p (), + group_match_null_string_p (); + +/* Structure for per-register (a.k.a. per-group) information. + This must not be longer than one word, because we push this value + onto the failure stack. Other register information, such as the + starting and ending positions (which are addresses), and the list of + inner groups (which is a bits list) are maintained in separate + variables. + + We are making a (strictly speaking) nonportable assumption here: that + the compiler will pack our bit fields into something that fits into + the type of `word', i.e., is something that fits into one item on the + failure stack. */ +typedef union +{ + fail_stack_elt_t word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +#define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} register_info_type; + +#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +#define IS_ACTIVE(R) ((R).bits.is_active) +#define MATCHED_SOMETHING(R) ((R).bits.matched_something) +#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) + + +/* Call this when have matched a real character; it sets `matched' flags + for the subexpressions which we are currently inside. Also records + that those subexprs have matched. */ +#define SET_REGS_MATCHED() \ + do \ + { \ + unsigned r; \ + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ + } \ + while (0) + + +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +#define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1) + +/* Registers are set to a sentinel when they haven't yet matched. */ +#define REG_UNSET_VALUE ((char *) -1) +#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) + + +/* Macros for dealing with the split strings in re_match_2. */ + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) + +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) + + +/* Free everything we malloc. */ +#ifdef REGEX_MALLOC +#define FREE_VAR(var) if (var) free (var); var = NULL +#define FREE_VARIABLES() \ + do { \ + FREE_VAR (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + } while (0) +#else /* not REGEX_MALLOC */ +/* Some MIPS systems (at least) want this to free alloca'd storage. */ +#define FREE_VARIABLES() alloca (0) +#endif /* not REGEX_MALLOC */ + + +/* These values must meet several constraints. They must not be valid + register values; since we have a limit of 255 registers (because + we use only one byte in the pattern for the register number), we can + use numbers larger than 255. They must differ by 1, because of + NUM_FAILURE_ITEMS above. And the value for the lowest register must + be larger than the value for the highest register, so we do not try + to actually save any registers when none are active. */ +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) + +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (bufp, string, size, pos, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, pos; + struct re_registers *regs; + { + return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); +} +#endif /* not emacs */ + + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + /* General temporaries. */ + int mcnt; + unsigned char *p1; + + /* Just past the end of the corresponding string. */ + const char *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + const char *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + const char *d, *dend; + + /* Where we are in the pattern, and the end of the pattern. */ + unsigned char *p = bufp->buffer; + register unsigned char *pend = p + bufp->used; + + /* We use this to map every character in the string. */ + char *translate = bufp->translate; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is + a ``dummy''; if a failure happens and the failure point is a dummy, + it gets discarded and the next next one is tried. */ + fail_stack_type fail_stack; +#ifdef DEBUG + static unsigned failure_id = 0; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + unsigned num_regs = bufp->re_nsub + 1; + + /* The currently active registers. */ + unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG; + unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ + const char **regstart, **regend; + + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ + const char **old_regstart, **old_regend; + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ + register_info_type *reg_info; + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; + const char **best_regstart, **best_regend; + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + const char *match_end = NULL; + + /* Used when we pop values we don't care about. */ + const char **reg_dummy; + register_info_type *reg_info_dummy; + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, const char *); + regend = REGEX_TALLOC (num_regs, const char *); + old_regstart = REGEX_TALLOC (num_regs, const char *); + old_regend = REGEX_TALLOC (num_regs, const char *); + best_regstart = REGEX_TALLOC (num_regs, const char *); + best_regend = REGEX_TALLOC (num_regs, const char *); + reg_info = REGEX_TALLOC (num_regs, register_info_type); + reg_dummy = REGEX_TALLOC (num_regs, const char *); + reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); + + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } + } +#ifdef REGEX_MALLOC + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = old_regstart = old_regend = best_regstart + = best_regend = reg_dummy = NULL; + reg_info = reg_info_dummy = (register_info_type *) NULL; + } +#endif /* REGEX_MALLOC */ + + /* The starting position is bogus. */ + if (pos < 0 || pos > size1 + size2) + { + FREE_VARIABLES (); + return -1; + } + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (stop <= size1) + { + end_match_1 = string1 + stop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ + if (size1 > 0 && pos <= size1) + { + d = string1 + pos; + dend = end_match_1; + } + else + { + d = string2 + pos - size1; + dend = end_match_2; + } + + DEBUG_PRINT1 ("The compiled pattern is: "); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { + DEBUG_PRINT2 ("\n0x%x: ", p); + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); + + /* If exceeds best match so far, save it. */ + if (!best_regs_set + || (same_str_p && d > match_end) + || (!same_str_p && !MATCHING_IN_FIRST_STRING)) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. */ + else if (best_regs_set) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } /* d != end_match_2 */ + + DEBUG_PRINT1 ("Accepting match.\n"); + + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + } + } + else + assert (bufp->regs_allocated == REGS_FIXED); + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 + : d - string2 + size1); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++) + { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { + regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]); + regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + } /* regs && !bufp->no_sub */ + + FREE_VARIABLES (); + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 + : string2 - size1); + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + return mcnt; + } + + /* Otherwise match next pattern command. */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((re_opcode_t) *p++)) +#else + switch ((re_opcode_t) *p++) +#endif + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH (); + if (translate[(unsigned char) *d++] != (char) *p++) + goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != (char) *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED (); + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + goto fail; + + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; + break; + + + case charset: + case charset_not: + { + register unsigned char c; + boolean not = (re_opcode_t) *(p - 1) == charset_not; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + + PREFETCH (); + c = TRANSLATE (*d); /* The character to match. */ + + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ + if (c < (unsigned) (*p * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + + SET_REGS_MATCHED (); + d++; + break; + } + + + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); + + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", + POINTER_TO_OFFSET (old_regstart[*p])); + + regstart[*p] = d; + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + break; + + + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ + case stop_memory: + DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + DEBUG_PRINT2 (" old_regend: %d\n", + POINTER_TO_OFFSET (old_regend[*p])); + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ + if (r == 0) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || (re_opcode_t) p[-3] == start_memory) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: + is_a_jump_n = true; + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (is_a_jump_n) + p1 += 2; + break; + + default: + /* do nothing */ ; + } + p1 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + { + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < *p + *(p + 1); r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if ((int) old_regend[r] >= (int) regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; + + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of as the register number. */ + case duplicate: + { + register const char *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : bcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); + + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(\(a*\)b*\)\2, we need the inner group. */ + + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; + + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; + + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } + + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; + + + /* A smart repeat ends with `maybe_pop_jump'. + We change it to either `pop_failure_jump' or `jump'. */ + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { + register unsigned char *p2 = p; + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. */ + while (p2 + 2 < pend + && ((re_opcode_t) *p2 == stop_memory + || (re_opcode_t) *p2 == start_memory)) + p2 += 3; /* Skip over args, too. */ + + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) + { + /* Consider what happens when matching ":\(.*\)" + against ":/". I don't really understand this code + yet. */ + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } + + else if ((re_opcode_t) *p2 == exactn + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) + { + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; + p1 = p + mcnt; + + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset + || (re_opcode_t) p1[3] == charset_not) + { + int not = (re_opcode_t) p1[3] == charset_not; + + if (c < (unsigned char) (p1[4] * BYTEWIDTH) + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!not) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + } + p -= 2; /* Point at relative address again. */ + if ((re_opcode_t) p[-1] != pop_failure_jump) + { + p[-1] = (unsigned char) jump; + DEBUG_PRINT1 (" Match => jump.\n"); + goto unconditional_jump; + } + /* Note fall through. */ + + + /* The end of a simple repeat has a pop_failure_jump back to + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + unsigned dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; + + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ + + + /* Unconditionally jump (without popping any failure points). */ + case jump: + unconditional_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ + DEBUG_PRINT2 ("(to 0x%x).\n", p); + break; + + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; + + + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (0, 0, -2); + goto unconditional_jump; + + + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (0, 0, -2); + break; + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); + } + else if (mcnt == 0) + { + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); + p[2] = (unsigned char) no_op; + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); + STORE_NUMBER (p1, mcnt); + break; + } + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; + + case notwordbound: + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + goto fail; + break; + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) + break; + goto fail; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + break; + goto fail; + +#ifdef emacs +#ifdef emacs19 + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; +#else /* not emacs19 */ + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point) + goto fail; + break; +#endif /* not emacs19 */ + + case syntaxspec: + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchsyntax; + + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + mcnt = (int) Sword; + matchsyntax: + PREFETCH (); + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + + case notsyntaxspec: + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchnotsyntax; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + mcnt = (int) Sword; + matchnotsyntax: + PREFETCH (); + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + +#else /* not emacs */ + case wordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + PREFETCH (); + if (!WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + PREFETCH (); + if (WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; +#endif /* not emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + if (!FAIL_STACK_EMPTY ()) + { /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); + + /* If this failure point is a dummy, try the next one. */ + if (!p) + goto fail; + + /* If we failed to the end of the pattern, don't examine *p. */ + assert (p <= pend); + if (p < pend) + { + boolean is_a_jump_n = false; + + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + + +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static boolean +group_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + /* Point to after the args to the start_memory. */ + unsigned char *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((re_opcode_t) *p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 3; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); + + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; + + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + assert (p1[1] == **p); + *p = p1 + 2; + return true; + + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return false; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static boolean +alt_match_null_string_p (p, end, reg_info) + unsigned char *p, *end; + register_info_type *reg_info; +{ + int mcnt; + unsigned char *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((re_opcode_t) *p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return true; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static boolean +common_op_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + boolean ret; + int reg_no; + unsigned char *p1 = *p; + + switch ((re_opcode_t) *p1++) + { + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + assert (reg_no > 0 && reg_no <= MAX_REGNUM); + ret = group_match_null_string_p (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return false; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return false; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += 2; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return false; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return false; + break; + + case set_number_at: + p1 += 4; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return false; + } + + *p = p1; + return true; +} /* common_op_match_null_string_p */ + + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +bcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate[*p1++] != translate[*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + int length; + struct re_pattern_buffer *bufp; +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = regex_compile (pattern, length, re_syntax_options, bufp); + + return re_error_msg[(int) ret]; +} + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them if this is an Emacs or POSIX compilation. */ + +#if !defined (emacs) && !defined (_POSIX_SOURCE) + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + return "Memory exhausted"; + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + + ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + /* Yes, we're discarding `const' here. */ + return (char *) re_error_msg[(int) ret]; +} + + +int +re_exec (s) + const char *s; +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} +#endif /* not emacs and not _POSIX_SOURCE */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' and `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *preg; + const char *pattern; + int cflags; +{ + reg_errcode_t ret; + unsigned syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + + /* Don't bother to use a fastmap when searching. This simplifies the + REG_NEWLINE case: if we used a fastmap, we'd have to put all the + characters after newlines into the fastmap. This way, we just try + every character. */ + preg->fastmap = 0; + + if (cflags & REG_ICASE) + { + unsigned i; + + preg->translate = (char *) malloc (CHAR_SET_SIZE); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? tolower (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ + ret = regex_compile (pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) ret = REG_EPAREN; + + return (int) ret; +} + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *preg; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; + int eflags; +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch, regoff_t); + regs.end = TALLOC (nmatch, regoff_t); + if (regs.start == NULL || regs.end == NULL) + return (int) REG_NOMATCH; + } + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + free (regs.end); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *preg; + char *errbuf; + size_t errbuf_size; +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = re_error_msg[errcode]; + + /* POSIX doesn't require that we do anything in this case, but why + not be nice. */ + if (! msg) + msg = "Success"; + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { + strncpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; + } + else + strcpy (errbuf, msg); + } + + return msg_size; +} + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} + +#endif /* not emacs */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ diff --git a/compat/regex.h b/compat/regex.h new file mode 100644 index 0000000000..408dd21034 --- /dev/null +++ b/compat/regex.h @@ -0,0 +1,490 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + + Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __REGEXP_LIBRARY_H__ +#define __REGEXP_LIBRARY_H__ + +/* POSIX says that must be included (by the caller) before + . */ + +#ifdef VMS +/* VMS doesn't have `size_t' in , even though POSIX says it + should be there. */ +#include +#endif + + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +#define RE_BACKSLASH_ESCAPE_IN_LISTS (1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +#define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +#define RE_SYNTAX_EMACS 0 + +#define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_UNMATCHED_RIGHT_PAREN_ORD) + +#define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS) + +#define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +#define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +#define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +#define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +#define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS + replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ +#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. Some systems + (erroneously) define this in other header files, but we want our + value, so remove any previous define. */ +#ifdef RE_DUP_MAX +#undef RE_DUP_MAX +#endif +#define RE_DUP_MAX ((1 << 15) - 1) + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (REG_EXTENDED << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (REG_ICASE << 1) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (REG_NEWLINE << 1) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + + +/* If any error codes are removed, changed, or added, update the + `re_error_msg' table in regex.c. */ +typedef enum +{ + REG_NOERROR = 0, /* Success. */ + REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + REG_BADPAT, /* Invalid pattern. */ + REG_ECOLLATE, /* Not implemented. */ + REG_ECTYPE, /* Invalid character class name. */ + REG_EESCAPE, /* Trailing backslash. */ + REG_ESUBREG, /* Invalid back reference. */ + REG_EBRACK, /* Unmatched left bracket. */ + REG_EPAREN, /* Parenthesis imbalance. */ + REG_EBRACE, /* Unmatched \{. */ + REG_BADBR, /* Invalid contents of \{\}. */ + REG_ERANGE, /* Invalid range end. */ + REG_ESPACE, /* Ran out of memory. */ + REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + REG_EEND, /* Premature end. */ + REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +struct re_pattern_buffer +{ +/* [[[begin pattern_buffer]]] */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are + sometimes used as array indexes. */ + unsigned char *buffer; + + /* Number of bytes to which `buffer' points. */ + unsigned long allocated; + + /* Number of bytes actually used in `buffer'. */ + unsigned long used; + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t syntax; + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ + char *fastmap; + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ + char *translate; + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ + unsigned can_be_null : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#define REGS_UNALLOCATED 0 +#define REGS_REALLOCATE 1 +#define REGS_FIXED 2 + unsigned regs_allocated : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned fastmap_accurate : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned no_sub : 1; + + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ + unsigned not_bol : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned not_eol : 1; + + /* If true, an anchor at a newline matches. */ + unsigned newline_anchor : 1; + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + + +/* search.c (search_buffer) in Emacs needs this one opcode value. It is + defined both in `regex.c' and here. */ +#define RE_EXACTN_VALUE 1 + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#ifndef RE_NREGS +#define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* To avoid duplicating every routine declaration -- once with a + prototype (if we are ANSI), and once without (if we aren't) -- we + use the following macro to declare argument types. This + unfortunately clutters up the declarations a bit, but I think it's + worth it. */ + +#if __STDC__ + +#define _RE_ARGS(args) args + +#else /* not __STDC__ */ + +#define _RE_ARGS(args) () + +#endif /* not __STDC__ */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern const char *re_compile_pattern + _RE_ARGS ((const char *pattern, int length, + struct re_pattern_buffer *buffer)); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern int re_search + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, int range, struct re_registers *regs)); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern int re_search_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern int re_match + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, struct re_registers *regs)); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern int re_match_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers + _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, + unsigned num_regs, regoff_t *starts, regoff_t *ends)); + +/* 4.2 bsd compatibility. */ +extern char *re_comp _RE_ARGS ((const char *)); +extern int re_exec _RE_ARGS ((const char *)); + +/* POSIX compatibility. */ +extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); +extern int regexec + _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags)); +extern size_t regerror + _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, + size_t errbuf_size)); +extern void regfree _RE_ARGS ((regex_t *preg)); + +#endif /* not __REGEXP_LIBRARY_H__ */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ From 3724812944c65714216ecdb87835835cf12f8870 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 1 Mar 2007 15:00:20 +0100 Subject: [PATCH 0097/3720] Better contrast of text and background of selected lines. The color -selectbackground is commonly dark, but so is the text (black). -highlightbackground is a bit lighter, hence, it offers better contrast in the selected entries while the selected entry still clearly stands out from the other entries. Signed-off-by: Johannes Sixt --- gitk | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gitk b/gitk index 8ffc10a9e5..3909445d8a 100755 --- a/gitk +++ b/gitk @@ -667,7 +667,7 @@ proc makewindow {} { pack .bright.sb -side right -fill y pack $cflist -side left -fill both -expand 1 $cflist tag configure highlight \ - -background [$cflist cget -selectbackground] + -background [$cflist cget -highlightbackground] $cflist tag configure bold -font [concat $mainfont bold] .pwbottom add .bright @@ -1755,7 +1755,7 @@ proc bolden {row font} { $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($row)] \ -outline {{}} -tags secsel \ - -fill [$canv cget -selectbackground]] + -fill [$canv cget -highlightbackground]] $canv lower $t } } @@ -1769,7 +1769,7 @@ proc bolden_name {row font} { $canv2 delete secsel set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \ -outline {{}} -tags secsel \ - -fill [$canv2 cget -selectbackground]] + -fill [$canv2 cget -highlightbackground]] $canv2 lower $t } } @@ -3885,15 +3885,15 @@ proc selectline {l isnew} { if {![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ - -tags secsel -fill [$canv cget -selectbackground]] + -tags secsel -fill [$canv cget -highlightbackground]] $canv lower $t $canv2 delete secsel set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \ - -tags secsel -fill [$canv2 cget -selectbackground]] + -tags secsel -fill [$canv2 cget -highlightbackground]] $canv2 lower $t $canv3 delete secsel set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \ - -tags secsel -fill [$canv3 cget -selectbackground]] + -tags secsel -fill [$canv3 cget -highlightbackground]] $canv3 lower $t if {$isnew} { From a352bda010a148d563a40a939ded2c5f9e558af9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 1 Mar 2007 16:02:23 +0100 Subject: [PATCH 0098/3720] Increase the pipe buffer size. It commonly happens that git-fetch-pack and git-upload-pack hit a deadlock in the initial commit id exchange, such that both try to write to the other end, but do not succeed. I have the suspicion that the reason is that both ends fill the pipe, but don't read. Increasing the pipe buffer helps, but is this the real cure? --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index dbc13f0c8a..9222626d28 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -106,7 +106,7 @@ int pipe(int filedes[2]) int fd; HANDLE h[2], parent; - if (_pipe(filedes, 4096, 0) < 0) + if (_pipe(filedes, 8192, 0) < 0) return -1; parent = GetCurrentProcess(); From f16b0ec3bdf089d94ca7dac4f8da95b9154abbff Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Mar 2007 10:05:27 +0100 Subject: [PATCH 0099/3720] Let the fake readlink(2) and symlink(2) functions report ENOSYS. Now that some symbolic link support is coming soon, let those functions report a more correct error than EINVAL or EFAULT. --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9222626d28..595c9956e1 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -7,13 +7,13 @@ unsigned int _CRT_fmode = _O_BINARY; int readlink(const char *path, char *buf, size_t bufsiz) { - errno = EINVAL; + errno = ENOSYS; return -1; } int symlink(const char *oldpath, const char *newpath) { - errno = EFAULT; + errno = ENOSYS; return -1; } From 3f6ad348ef80bb1143ac4ee27a7f16a9491f0e23 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Mar 2007 10:10:31 +0100 Subject: [PATCH 0100/3720] Provide the missing S_ISLNK and S_IFLNK macros. Even though the file systems on Windows do not support symbolic links, repositories can still contain information about symbolic links, which is interrogated at many occasions. Without the correct definitions S_ISLNK and S_IFLNK, symbolic link information in the repository is not recognized and treated as corruption. --- git-compat-util.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 8d444e8c5a..09bebab73d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -298,8 +298,8 @@ static inline int prefixcmp(const char *str, const char *prefix) // MinGW #ifndef S_ISLNK -#define S_ISLNK(x) 0 -#define S_IFLNK 0 +#define S_IFLNK 0120000 /* Symbolic link */ +#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #endif #ifndef S_ISGRP From a1f4d20db83ed1bf24b0030e3f81dab497a1e00a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Mar 2007 15:27:32 +0100 Subject: [PATCH 0101/3720] Update README.MinGW: regex is now included; spaces in MSYS path are OK --- README.MinGW | 9 --------- 1 file changed, 9 deletions(-) diff --git a/README.MinGW b/README.MinGW index a8ad34bc4b..bf3b4648a0 100644 --- a/README.MinGW +++ b/README.MinGW @@ -26,17 +26,8 @@ In order to compile this code you need: - additional libraries: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz - regex-0.12.tar.gz (from the GNU site) - compile this into regex.o, ar it into libregex.a - and install it in /mingw/lib, include file into - /mingw/include tcltk-8.4.1-1.exe (for gitk, git-gui) -It is absolutely necessary that you install MSYS in a path that does not -contain special characters, like spaces. I have it in - - D:\MSYS\1.0 - D:\MSYS\1.0\mingw STATUS ------ From fa807fcb28e11e38ef25ec78494001b50e1caeec Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 12 Jan 2007 14:10:50 +0100 Subject: [PATCH 0102/3720] Revert "Makefile: remove $foo when $foo.exe is built/installed." This reverts commit 6fc301bbf68decbda369402a11ef215391bdd533. Appearently, MSYS's shell returns success for -f foo if foo.exe exists. Hence, this patch removes *all* .exe files - not quite what we want. --- Makefile | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 637ac3ed94..8fa827d879 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # The default target of this Makefile is... -all:: +all: # Define NO_OPENSSL environment variable if you do not have OpenSSL. # This also implies MOZILLA_SHA1. @@ -657,12 +657,9 @@ export prefix gitexecdir TAR INSTALL DESTDIR SHELL_PATH template_dir ### Build rules -all:: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi -ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$p';) -endif +all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi -all:: +all: $(MAKE) -C git-gui all $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all $(MAKE) -C templates NOEXECTEMPL='$(NOEXECTEMPL)' @@ -907,9 +904,6 @@ install: all '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ fi $(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) -ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) -endif install-doc: $(MAKE) -C Documentation install From 8217e459b13d79c1114828a0fc947f705f3e59cc Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Mar 2007 13:45:58 +0100 Subject: [PATCH 0103/3720] Make open(2) a macro that it replaces "/dev/null" by "nul" on MinGW. --- git-compat-util.h | 4 ++++ run-command.c | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 0d62dc8149..bf9dbe288a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -397,6 +397,10 @@ static inline int git_unlink(const char *pathname) { } #define unlink git_unlink +#define open(P, F, M...) \ + (__builtin_constant_p(*(P)) && !strcmp(P, "/dev/null") ? \ + open("nul", F, ## M) : open(P, F, ## M)) + #include struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); diff --git a/run-command.c b/run-command.c index 79ca6cc9df..0dcbcd2b8a 100644 --- a/run-command.c +++ b/run-command.c @@ -10,11 +10,7 @@ int run_command_v_opt(const char **argv, int flags) int fd_o[2] = { -1, -1 }; if (flags & RUN_COMMAND_NO_STDIN) { -#ifndef __MINGW32__ fd_i[0] = open("/dev/null", O_RDWR); -#else - fd_i[0] = open("nul", O_RDWR); -#endif } if (flags & RUN_COMMAND_STDOUT_TO_STDERR) fd_o[1] = dup(2); From 1d102315e550757a13d6a283223073182c358805 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Mar 2007 15:25:39 +0100 Subject: [PATCH 0104/3720] Adjust git diff invocation in t3100 since git diff is used instead of diff. --- t/t3100-ls-tree-restrict.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index e3da8508f4..8ca1a8a1d5 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -23,15 +23,9 @@ test "$no_symlinks" && { test "$1" = -s && shift date > "$2" } - DIFF=$(which diff) function diff () { - opt= - if test "$1" = -u; then - opt="$1" - shift - fi sed s/^120000/100644/ < "$1" > "$1".doof - $DIFF $opt "$1".doof "$2" + git diff "$1".doof "$2" } } @@ -53,7 +47,7 @@ _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" test_output () { sed -e "s/ $_x40 / X /" check - git diff expected check + diff expected check } test_expect_success \ From 520c945240da7dc74c5d04d6fa81bab42dcea38f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Mar 2007 19:51:16 +0100 Subject: [PATCH 0105/3720] Reindent run-command.c to bring it closer to the upstream version. Let's hope that this simplifies merging a bit. --- run-command.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/run-command.c b/run-command.c index 0dcbcd2b8a..00deab0264 100644 --- a/run-command.c +++ b/run-command.c @@ -9,16 +9,17 @@ int run_command_v_opt(const char **argv, int flags) int fd_i[2] = { -1, -1 }; int fd_o[2] = { -1, -1 }; - if (flags & RUN_COMMAND_NO_STDIN) { - fd_i[0] = open("/dev/null", O_RDWR); - } - if (flags & RUN_COMMAND_STDOUT_TO_STDERR) - fd_o[1] = dup(2); - - if (flags & RUN_GIT_CMD) { - pid = spawnv_git_cmd(argv, fd_i, fd_o); - } else { - pid = spawnvpe_pipe(argv[0], argv, environ, fd_i, fd_o); + { + if (flags & RUN_COMMAND_NO_STDIN) { + fd_i[0] = open("/dev/null", O_RDWR); + } + if (flags & RUN_COMMAND_STDOUT_TO_STDERR) + fd_o[1] = dup(2); + if (flags & RUN_GIT_CMD) { + pid = spawnv_git_cmd(argv, fd_i, fd_o); + } else { + pid = spawnvpe_pipe(argv[0], argv, environ, fd_i, fd_o); + } } if (pid < 0) return -ERR_RUN_COMMAND_FORK; From 69fdfa18b55fdf5a2245473ef01c656d4bced269 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 23 Mar 2007 10:58:53 +0100 Subject: [PATCH 0106/3720] Work around missing stat(1) command. MinGW does not have the stat command. Use ls -l to find out the size of a file. --- t/t5300-pack-object.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index b985bc5db5..48c38cfb4d 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -26,6 +26,12 @@ corrupt() ) < $1 > $2 } +test "$no_symlinks" && { + stat() { + ls -l "$3" | tr -s ' ' ' ' | cut -d' ' -f5 + } +} + test_expect_success \ 'setup' \ 'rm -f .git/index* From bff909b88259160b50823f277ea8c1426e4f7aa0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 23 Mar 2007 13:25:02 +0100 Subject: [PATCH 0107/3720] Protect {tree} from being expanded by the shell. Some shells seem to treat {tree} as the instruction to brace-expand the word even if the resulting word is not a valid file. During this process the braces {} are lost. To avoid this, the opening brace is escaped. --- t/t5515-fetch-merge-logic.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 6c9cc67508..59f65e60ac 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -20,7 +20,7 @@ test_expect_success setup ' git add file && git commit -a -m One && git tag tag-one && - git tag tag-one-tree HEAD^{tree} && + git-tag tag-one-tree HEAD^\{tree} && git branch one && echo two >> file && @@ -31,7 +31,7 @@ test_expect_success setup ' echo three >> file && git commit -a -m Three && git tag -a -m "Tag Three" tag-three && - git tag -a -m "Tag Three file" tag-three-file HEAD^{tree}:file && + git-tag -a -m "Tag Three file" tag-three-file HEAD^\{tree}:file && git branch three && echo master >> file && From 6b943f171b24e6eb2bf3827554d2536410ed7fe8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 23 Mar 2007 10:57:05 +0100 Subject: [PATCH 0108/3720] Fix PRIuMAX definition for MinGW. Since MinGW calls into Microsoft's MSVCRT.DLL, it must use the printf format that this DLL uses for 64bit integers, which is %I64u instead of %llu. --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index bf9dbe288a..428f171379 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -74,7 +74,11 @@ #endif #ifndef PRIuMAX +#ifndef __MINGW32__ #define PRIuMAX "llu" +#else +#define PRIuMAX "I64u" +#endif #endif #ifdef __GNUC__ From c65b79715c07b588880c1b462cbabe980b162b78 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 13:23:22 +0100 Subject: [PATCH 0109/3720] Avoid Windows's find by using the full path of /usr/bin/find. --- git-clone.sh | 6 +++--- git-ls-remote.sh | 2 +- git-repack.sh | 2 +- t/t0000-basic.sh | 6 +++--- t/t1200-tutorial.sh | 2 +- t/t2001-checkout-cache-clash.sh | 2 +- t/t3100-ls-tree-restrict.sh | 2 +- t/t3101-ls-tree-dirname.sh | 2 +- t/t4112-apply-renames.sh | 2 +- t/t5000-tar-tree.sh | 14 +++++++------- t/t5300-pack-object.sh | 6 +++--- t/t9200-git-cvsexportcommit.sh | 2 +- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 513b574d13..1cbc2f5858 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -224,7 +224,7 @@ yes,yes) no) # See if we can hardlink and drop "l" if not. sample_file=$(cd "$repo" && \ - find objects -type f -print | sed -e 1q) + /usr/bin/find objects -type f -print | sed -e 1q) # objects directory should not be empty since we are cloning! test -f "$repo/$sample_file" || exit @@ -236,7 +236,7 @@ yes,yes) fi && rm -f "$GIT_DIR/objects/sample" && cd "$repo" && - find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 + /usr/bin/find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 ;; yes) mkdir -p "$GIT_DIR/objects/info" @@ -354,7 +354,7 @@ then ( test -f "$GIT_DIR/$remote_top/master" && echo "master" cd "$GIT_DIR/$remote_top" && - find . -type f -print | sed -e 's/^\.\///' + /usr/bin/find . -type f -print | sed -e 's/^\.\///' ) | ( done=f while read name diff --git a/git-ls-remote.sh b/git-ls-remote.sh index a6ed99a7c5..145fc38c79 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -79,7 +79,7 @@ rsync://* ) head=$(cat "$tmpdir/$head") || exit esac && echo "$head HEAD" - (cd $tmpdir && find refs -type f) | + (cd $tmpdir && /usr/bin/find refs -type f) | while read path do cat "$tmpdir/$path" | tr -d '\012' diff --git a/git-repack.sh b/git-repack.sh index ddfa8b44a1..bf0bdcf4ff 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -46,7 +46,7 @@ case ",$all_into_one," in ;; ,t,) if [ -d "$PACKDIR" ]; then - for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \ + for e in `cd "$PACKDIR" && /usr/bin/find . -type f -name '*.pack' \ | sed -e 's/^\.\///' -e 's/\.pack$//'` do if [ -e "$PACKDIR/$e.keep" ]; then diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 81ec70ff93..66898afc4f 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -50,14 +50,14 @@ test "$no_symlinks" && { # git-init has been done in an empty repository. # make sure it is empty. -find .git/objects -type f -print >should-be-empty +/usr/bin/find .git/objects -type f -print >should-be-empty test_expect_success \ '.git/objects should be empty after git-init in an empty repo.' \ 'cmp -s /dev/null should-be-empty' # also it should have 2 subdirectories; no fan-out anymore, pack, and info. # 3 is counting "objects" itself -find .git/objects -type d -print >full-of-directories +/usr/bin/find .git/objects -type d -print >full-of-directories test_expect_success \ '.git/objects should have 3 subdirectories.' \ 'test $(wc -l < full-of-directories) = 3' @@ -112,7 +112,7 @@ do done test_expect_success \ 'adding various types of objects with git-update-index --add.' \ - 'find path* ! -type d -print | xargs git-update-index --add' + '/usr/bin/find path* ! -type d -print | xargs git-update-index --add' # Show them and see that matches what we expect. test_expect_success \ diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh index ca2c30f7af..97bf4dc517 100755 --- a/t/t1200-tutorial.sh +++ b/t/t1200-tutorial.sh @@ -156,7 +156,7 @@ test_expect_success 'git show-branch' 'cmp show-branch2.expect show-branch2.outp test_expect_success 'git repack' 'git repack' test_expect_success 'git prune-packed' 'git prune-packed' -test_expect_failure '-> only packed objects' 'find -type f .git/objects/[0-9a-f][0-9a-f]' +test_expect_failure '-> only packed objects' '/usr/bin/find -type f .git/objects/[0-9a-f][0-9a-f]' test_done diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh index 825119b01c..05c2262466 100755 --- a/t/t2001-checkout-cache-clash.sh +++ b/t/t2001-checkout-cache-clash.sh @@ -23,7 +23,7 @@ the symlink path1 and create directory path1 and file path1/file1. show_files() { # show filesystem files, just [-dl] for type and name - find path? -ls | + /usr/bin/find path? -ls | sed -e 's/^[0-9]* * [0-9]* * \([-bcdl]\)[^ ]* *[0-9]* *[^ ]* *[^ ]* *[0-9]* [A-Z][a-z][a-z] [0-9][0-9] [^ ]* /fs: \1 /' # what's in the cache, just mode and name git-ls-files --stage | diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 8ca1a8a1d5..40501798d1 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -38,7 +38,7 @@ test_expect_success \ echo Lo >path2/foo && ln -s ../path1 path2/bazbo && echo Mi >path2/baz/b && - find path? \( -type f -o -type l \) -print | + /usr/bin/find path? \( -type f -o -type l \) -print | xargs git-update-index --add && tree=`git-write-tree` && echo $tree' diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh index 087929a4bf..eb3df85eff 100755 --- a/t/t3101-ls-tree-dirname.sh +++ b/t/t3101-ls-tree-dirname.sh @@ -34,7 +34,7 @@ test_expect_success \ mkdir path3 && echo 111 >path3/1.txt && echo 222 >path3/2.txt && - find *.txt path* \( -type f -o -type l \) -print | + /usr/bin/find *.txt path* \( -type f -o -type l \) -print | xargs git-update-index --add && tree=`git-write-tree` && echo $tree' diff --git a/t/t4112-apply-renames.sh b/t/t4112-apply-renames.sh index 69e9603c78..bfcb8821c8 100755 --- a/t/t4112-apply-renames.sh +++ b/t/t4112-apply-renames.sh @@ -115,7 +115,7 @@ rename to include/arch/m32r/klibc/archsetjmp.h +#endif /* _KLIBC_ARCHSETJMP_H */ EOF -find klibc -type f -print | xargs git-update-index --add -- +/usr/bin/find klibc -type f -print | xargs git-update-index --add -- test_expect_success 'check rename/copy patch' 'git-apply --check patch' diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index b00acafce0..f46ea1542e 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -45,12 +45,12 @@ test_expect_success \ (p=long_path_to_a_file && cd a && for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && echo text >file_with_long_path) && - (cd a && find .) | sort >a.lst' + (cd a && /usr/bin/find .) | sort >a.lst' test_expect_success \ 'add files to repository' \ - 'find a -type f | xargs git-update-index --add && - find a -type l | xargs git-update-index --add && + '/usr/bin/find a -type f | xargs git-update-index --add && + /usr/bin/find a -type l | xargs git-update-index --add && treeid=`git-write-tree` && echo $treeid >treeid && git-update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \ @@ -79,7 +79,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd b/a && find .) | sort >b.lst && + '(cd b/a && /usr/bin/find .) | sort >b.lst && diff a.lst b.lst' test_expect_success \ @@ -96,7 +96,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd c/prefix/a && find .) | sort >c.lst && + '(cd c/prefix/a && /usr/bin/find .) | sort >c.lst && diff a.lst c.lst' test_expect_success \ @@ -113,7 +113,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd d/a && find .) | sort >d.lst && + '(cd d/a && /usr/bin/find .) | sort >d.lst && diff a.lst d.lst' test_expect_success \ @@ -130,7 +130,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd e/prefix/a && find .) | sort >e.lst && + '(cd e/prefix/a && /usr/bin/find .) | sort >e.lst && diff a.lst e.lst' test_expect_success \ diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index aafb976a75..c1d34de954 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -75,7 +75,7 @@ cd "$TRASH/.git2" test_expect_success \ 'check unpack without delta' \ - '(cd ../.git && find objects -type f -print) | + '(cd ../.git && /usr/bin/find objects -type f -print) | while read path do cmp $path ../.git/$path || { @@ -105,7 +105,7 @@ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ 'check unpack with REF_DELTA' \ - '(cd ../.git && find objects -type f -print) | + '(cd ../.git && /usr/bin/find objects -type f -print) | while read path do cmp $path ../.git/$path || { @@ -135,7 +135,7 @@ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ 'check unpack with OFS_DELTA' \ - '(cd ../.git && find objects -type f -print) | + '(cd ../.git && /usr/bin/find objects -type f -print) | while read path do cmp $path ../.git/$path || { diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 4efa0c926c..e91b5a8437 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -174,7 +174,7 @@ test_expect_success \ if p="Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" && mkdir -p "tst/$p" && date >"tst/$p/day" && - found=$(find tst -type f -print) && + found=$(/usr/bin/find tst -type f -print) && test "z$found" = "ztst/$p/day" && rm -fr tst then From 70db4398cd3f4fb96b6100a28677d4f21116f19a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:15:58 +0100 Subject: [PATCH 0110/3720] Avoid Windows's sort by using the full path of /usr/bin/sort. --- check-builtins.sh | 2 +- generate-cmdlist.sh | 2 +- git-ls-remote.sh | 2 +- git-mergetool.sh | 4 +-- git-tag.sh | 2 +- t/t0000-basic.sh | 2 +- t/t5000-tar-tree.sh | 10 +++---- t/t6003-rev-list-topo-order.sh | 2 +- t/t9107-git-svn-migrate.sh | 2 +- t/t9200-git-cvsexportcommit.sh | 50 +++++++++++++++++----------------- 10 files changed, 39 insertions(+), 39 deletions(-) diff --git a/check-builtins.sh b/check-builtins.sh index d6fe6cf174..cd09309838 100755 --- a/check-builtins.sh +++ b/check-builtins.sh @@ -9,7 +9,7 @@ EOF } | make -f - sayIt 2>/dev/null | sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p' | -sort | +/usr/bin/sort | { bad=0 while read builtin diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index 975777f05e..a0a938aa08 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -9,7 +9,7 @@ struct cmdname_help struct cmdname_help common_cmds[] = {" -sort <<\EOF | +/usr/bin/sort <<\EOF | add apply archive diff --git a/git-ls-remote.sh b/git-ls-remote.sh index 145fc38c79..7bc2ab884f 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -98,7 +98,7 @@ rsync://* ) fi ;; esac | -sort -t ' ' -k 2 | +/usr/bin/sort -t ' ' -k 2 | while read sha1 path do case "$sha1" in diff --git a/git-mergetool.sh b/git-mergetool.sh index e62351bcba..7d1df52ac7 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -344,13 +344,13 @@ case "$merge_tool" in esac if test $# -eq 0 ; then - files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u` + files=`git ls-files -u | sed -e 's/^[^ ]* //' | /usr/bin/sort -u` if test -z "$files" ; then echo "No files need merging" exit 0 fi echo Merging the files: $files - git ls-files -u | sed -e 's/^[^ ]* //' | sort -u | while read i + git ls-files -u | sed -e 's/^[^ ]* //' | /usr/bin/sort -u | while read i do printf "\n" merge_file "$i" < /dev/tty > /dev/tty diff --git a/git-tag.sh b/git-tag.sh index 4a0a7b6607..47d7c0bb16 100755 --- a/git-tag.sh +++ b/git-tag.sh @@ -32,7 +32,7 @@ do set x . ;; esac shift - git rev-parse --symbolic --tags | sort | grep "$@" + git rev-parse --symbolic --tags | /usr/bin/sort | grep "$@" exit $? ;; -m) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 66898afc4f..534cad51c8 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -289,7 +289,7 @@ test_expect_success \ 'commit2=$(echo NO | git-commit-tree $P -p $commit0 -p $commit0) && parent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | - sort -u) && + /usr/bin/sort -u) && test "z$commit0" = "z$parent" && numparent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index f46ea1542e..766ac165c2 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -45,7 +45,7 @@ test_expect_success \ (p=long_path_to_a_file && cd a && for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && echo text >file_with_long_path) && - (cd a && /usr/bin/find .) | sort >a.lst' + (cd a && /usr/bin/find .) | /usr/bin/sort >a.lst' test_expect_success \ 'add files to repository' \ @@ -79,7 +79,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd b/a && /usr/bin/find .) | sort >b.lst && + '(cd b/a && /usr/bin/find .) | /usr/bin/sort >b.lst && diff a.lst b.lst' test_expect_success \ @@ -96,7 +96,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd c/prefix/a && /usr/bin/find .) | sort >c.lst && + '(cd c/prefix/a && /usr/bin/find .) | /usr/bin/sort >c.lst && diff a.lst c.lst' test_expect_success \ @@ -113,7 +113,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd d/a && /usr/bin/find .) | sort >d.lst && + '(cd d/a && /usr/bin/find .) | /usr/bin/sort >d.lst && diff a.lst d.lst' test_expect_success \ @@ -130,7 +130,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd e/prefix/a && /usr/bin/find .) | sort >e.lst && + '(cd e/prefix/a && /usr/bin/find .) | /usr/bin/sort >e.lst && diff a.lst e.lst' test_expect_success \ diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh index d99a9ad39e..cbf46dec42 100755 --- a/t/t6003-rev-list-topo-order.sh +++ b/t/t6003-rev-list-topo-order.sh @@ -10,7 +10,7 @@ test_description='Tests git-rev-list --topo-order functionality' list_duplicates() { - "$@" | sort | uniq -d + "$@" | /usr/bin/sort | uniq -d } date >path0 diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index dc2afdaa45..2665b57de9 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -65,7 +65,7 @@ test_expect_success 'multi-fetch works on partial urls + paths' " for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do git rev-parse --verify refs/remotes/\$i^0 >> refs.out || exit 1; done && - test -z \"\`sort < refs.out | uniq -d\`\" && + test -z \"\`/usr/bin/sort < refs.out | uniq -d\`\" && for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do for j in trunk a b tags/0.1 tags/0.2 tags/0.3; do if test \$j != \$i; then continue; fi diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index e91b5a8437..8e5722245d 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -43,10 +43,10 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git cvsexportcommit -c $id && - test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.1/" && - test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "newfile2.txt/1.1/" && - test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "newfile3.png/1.1/-kb" && - test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.1/" && + test "$(echo $(/usr/bin/sort B/CVS/Entries|cut -d/ -f2,3,5))" = "newfile2.txt/1.1/" && + test "$(echo $(/usr/bin/sort C/CVS/Entries|cut -d/ -f2,3,5))" = "newfile3.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.1/-kb" && diff A/newfile1.txt ../A/newfile1.txt && diff B/newfile2.txt ../B/newfile2.txt && diff C/newfile3.png ../C/newfile3.png && @@ -67,12 +67,12 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git cvsexportcommit -c $id && - test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" && - test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.2/-kb" && - test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && - test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" && + test "$(echo $(/usr/bin/sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.2/-kb" && + test "$(echo $(/usr/bin/sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && + test "$(echo $(/usr/bin/sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && diff A/newfile1.txt ../A/newfile1.txt && diff D/newfile4.png ../D/newfile4.png && diff E/newfile5.txt ../E/newfile5.txt && @@ -115,12 +115,12 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git cvsexportcommit -c $id && - test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" && - test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && - test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" && + test "$(echo $(/usr/bin/sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && + test "$(echo $(/usr/bin/sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && diff A/newfile1.txt ../A/newfile1.txt && diff E/newfile5.txt ../E/newfile5.txt && diff F/newfile6.png ../F/newfile6.png @@ -133,12 +133,12 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git cvsexportcommit -c $id && - test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && - test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort A/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && + test "$(echo $(/usr/bin/sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && diff E/newfile5.txt ../E/newfile5.txt && diff F/newfile6.png ../F/newfile6.png )' @@ -154,7 +154,7 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git-cvsexportcommit -c $id && - test "$(echo $(sort "G g/CVS/Entries"|cut -d/ -f2,3,5))" = "with spaces.png/1.1/-kb with spaces.txt/1.1/" + test "$(echo $(/usr/bin/sort "G g/CVS/Entries"|cut -d/ -f2,3,5))" = "with spaces.png/1.1/-kb with spaces.txt/1.1/" )' test_expect_success \ @@ -166,7 +166,7 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git-cvsexportcommit -c $id - test "$(echo $(sort "G g/CVS/Entries"|cut -d/ -f2,3,5))" = "with spaces.png/1.2/-kb with spaces.txt/1.2/" + test "$(echo $(/usr/bin/sort "G g/CVS/Entries"|cut -d/ -f2,3,5))" = "with spaces.png/1.2/-kb with spaces.txt/1.2/" )' # Some filesystems mangle pathnames with UTF-8 characters -- @@ -191,7 +191,7 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git-cvsexportcommit -v -c $id && - test "$(echo $(sort Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/CVS/Entries|cut -d/ -f2,3,5))" = "gårdetsågårdet.png/1.1/-kb gårdetsågårdet.txt/1.1/" + test "$(echo $(/usr/bin/sortsort Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/CVS/Entries|cut -d/ -f2,3,5))" = "gårdetsågårdet.png/1.1/-kb gårdetsågårdet.txt/1.1/" )' fi From e479ea2f911b8c70a269ba59372a4fef90f8907c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 11 Apr 2007 15:26:08 +0200 Subject: [PATCH 0111/3720] Turn builtin_exec_path into a function. builtin_exec_path returns the hard-coded installation path, which is used as the ultimate fallback to look for git commands. Making it into a function enables us to return a computed value instead of just a constant string. --- exec_cmd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 4e8125aab8..946a62c9e5 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -5,9 +5,13 @@ #define MAX_ARGS 32 extern char **environ; -static const char *builtin_exec_path = GIT_EXEC_PATH; static const char *current_exec_path; +static const char *builtin_exec_path(void) +{ + return GIT_EXEC_PATH; +} + void git_set_exec_path(const char *exec_path) { current_exec_path = exec_path; @@ -27,7 +31,7 @@ const char *git_exec_path(void) return env; } - return builtin_exec_path; + return builtin_exec_path(); } @@ -37,7 +41,7 @@ int execv_git_cmd(const char **argv) int i; const char *paths[] = { current_exec_path, getenv(EXEC_PATH_ENVIRONMENT), - builtin_exec_path }; + builtin_exec_path() }; for (i = 0; i < ARRAY_SIZE(paths); ++i) { size_t len; @@ -146,7 +150,7 @@ int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) pid_t pid; const char *paths[] = { current_exec_path, getenv(EXEC_PATH_ENVIRONMENT), - builtin_exec_path }; + builtin_exec_path() }; char p[3][PATH_MAX + 1]; char *usedpaths[4], **up = usedpaths; const char *tmp; From 00a4ff4f3f8ec7e6b3ac15456f00b22b03f438ae Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 11 Apr 2007 16:02:45 +0200 Subject: [PATCH 0112/3720] Compute the ultimate fallback for exec_path from the program invocation. Since on Windows the user is fairly free where to install programs, we cannot rely on a hard-coded path. We use the program name to derive the installation directory and use that as exec_path. The possiblity to have just the git wrapper in the PATH and let it invoke the toolset is sacrificed. --- exec_cmd.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/exec_cmd.c b/exec_cmd.c index 946a62c9e5..a9886b87fd 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,7 +9,36 @@ static const char *current_exec_path; static const char *builtin_exec_path(void) { +#ifndef __MINGW32__ return GIT_EXEC_PATH; +#else + int len; + char *p, *q, *sl; + static char *ep; + if (ep) + return ep; + + len = strlen(_pgmptr); + if (len < 2) + return ep = "."; + + p = ep = xmalloc(len+1); + q = _pgmptr; + sl = NULL; + /* copy program name, turn '\\' into '/', skip last part */ + while ((*p = *q)) { + if (*q == '\\' || *q == '/') { + *p = '/'; + sl = p; + } + p++, q++; + } + if (sl) + *sl = '\0'; + else + ep[0] = '.', ep[1] = '\0'; + return ep; +#endif } void git_set_exec_path(const char *exec_path) From 5cebf637374fdaa59c27f3732d3df140a23a7b59 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 12 Apr 2007 15:00:53 +0200 Subject: [PATCH 0113/3720] Turn backslashes in path specifiers into forward-slashes. --- setup.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/setup.c b/setup.c index b6a1c299a3..a66f479944 100644 --- a/setup.c +++ b/setup.c @@ -1,8 +1,15 @@ #include "cache.h" +#ifdef __MINGW32__ +static inline int is_dir_sep(char c) { return c == '/' || c == '\\'; } +#else +static inline int is_dir_sep(char c) { return c == '/'; } +#endif + const char *prefix_path(const char *prefix, int len, const char *path) { const char *orig = path; + int do_pfx; for (;;) { char c; if (*path != '.') @@ -14,7 +21,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) break; } /* "./" */ - if (c == '/') { + if (is_dir_sep(c)) { path += 2; continue; } @@ -23,7 +30,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) c = path[2]; if (!c) path += 2; - else if (c == '/') + else if (is_dir_sep(c)) path += 3; else break; @@ -33,15 +40,31 @@ const char *prefix_path(const char *prefix, int len, const char *path) if (!len) die("'%s' is outside repository", orig); len--; - } while (len && prefix[len-1] != '/'); + } while (len && !is_dir_sep(prefix[len-1])); continue; } - if (len) { + do_pfx = len; +#ifdef __MINGW32__ + /* we want to convert '\' in path to '/' (prefix already has '/') */ + { + const char *p = path; + while (!do_pfx && *p) { + do_pfx = *p++ == '\\'; + } + } +#endif + if (do_pfx) { int speclen = strlen(path); char *n = xmalloc(speclen + len + 1); + char *p; memcpy(n, prefix, len); memcpy(n + len, path, speclen+1); +#ifdef __MINGW32__ + for (p = n + len; *p; p++) + if (*p == '\\') + *p = '/'; +#endif path = n; } return path; @@ -55,10 +78,24 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; +#ifndef __MINGW32__ if (!pfx || !*pfx || arg[0] == '/') return arg; +#else + char *p; + /* don't add prefix to absolute paths */ + const int is_absolute = + is_dir_sep(arg[0]) || + (arg[0] && arg[1] == ':' && is_dir_sep(arg[2])); + if (is_absolute) + pfx_len = 0; + else +#endif memcpy(path, pfx, pfx_len); strcpy(path + pfx_len, arg); + for (p = path + pfx_len; *p; p++) + if (*p == '\\') + *p = '/'; return path; } From 5009b5450d9b15293199d5c0131cccefc8a3df72 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 12 Apr 2007 13:46:23 +0200 Subject: [PATCH 0114/3720] Revert "git-gui: Don't create empty (same tree as parent) commits." This reverts commit 51bd9d7b8cf29e0e441531fb0a671cc7093f278b. It introduced a git invocation that involves ^{tree}. It seems that MSYS's wish does some quoting for Bourne shells, in particular, escape the first '{', but then it uses cmd.exe to run the command, which does not remove the backslash, so that the resulting ref expression ends up in git's guts as unrecognizable garbage. --- git-gui/git-gui.sh | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 60e79ca1b0..5e901b5ecc 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,24 +1269,6 @@ proc commit_committree {fd_wt curHEAD msg} { return } - # -- Verify this wasn't an empty change. - # - if {$commit_type eq {normal}} { - set old_tree [git rev-parse "$PARENT^{tree}"] - if {$tree_id eq $old_tree} { - info_popup {No changes to commit. - -No files were modified by this commit and it -was not a merge commit. - -A rescan will be automatically started now. -} - unlock_index - rescan {set ui_status_value {No changes to commit.}} - return - } - } - # -- Build the message. # set msg_p [gitdir COMMIT_EDITMSG] From 390b6df11cc5359679227fe29a6d251b042a3ed7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 13 Apr 2007 09:53:43 +0200 Subject: [PATCH 0115/3720] Quote the script name before invoking the interpreter. When the argument vector for the interpreter invocation is assembled, the original arguments were already quoted when necessary, but the script name was not. If the script lives in a directory whose names contains spaces, the interpreter would not find the script. --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 595c9956e1..14fabcbbc0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -279,7 +279,7 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) for (n = 0; argv[n];) n++; sh_argv = xmalloc((n+2)*sizeof(char*)); sh_argv[0] = interpr; - sh_argv[1] = cmd; + sh_argv[1] = quote_arg(cmd); quote_argv(&sh_argv[2], &argv[1]); n = spawnvpe(_P_WAIT, interpr, sh_argv, env); if (n == -1) From b953c77a5b55ff3b453c3500fbb42d97950fd8b4 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 19 Apr 2007 18:34:03 +0200 Subject: [PATCH 0116/3720] Allow a relative builtin template directory. In order to make git relocatable (i.e. not have the prefix compiled-in) the template directory must depend on the location where this git instance is found, which is GIT_EXEC_DIR. The exec path is prepended only to the compiled-in default directory if it is relative. Any relative directories that are specified via environment variable or the --exec-dir switch are taken as is. Signed-off-by: Johannes Sixt --- builtin-init-db.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index 4df9fd0fad..ecf3db954a 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -130,10 +130,19 @@ static void copy_templates(const char *git_dir, int len, const char *template_di int template_len; DIR *dir; - if (!template_dir) { + if (!template_dir) template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); - if (!template_dir) - template_dir = DEFAULT_GIT_TEMPLATE_DIR; + if (!template_dir) { + /* + * if the hard-coded template is relative, it is + * interpreted relative to the exec_dir + */ + template_dir = DEFAULT_GIT_TEMPLATE_DIR; + if (template_dir[0] != '/' && template_dir[1] != ':') { + const char *exec_path = git_exec_path(); + template_dir = prefix_path(exec_path, strlen(exec_path), + template_dir); + } } strcpy(template_path, template_dir); template_len = strlen(template_path); From 2d84ffaf0da5f8ab0143b30cce254d7e6ea1e7a4 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 19 Apr 2007 18:36:01 +0200 Subject: [PATCH 0117/3720] MinGW uses a relative default template_dir. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 87979807fb..5510ebac7b 100644 --- a/Makefile +++ b/Makefile @@ -455,6 +455,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) EXTLIBS += -lws2_32 X = .exe NOEXECTEMPL = .noexec + template_dir = ../share/git-core/templates/ endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From 6433ce0f9648e5cce13defd83338e7b8e19b8d1b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 19 Apr 2007 18:47:45 +0200 Subject: [PATCH 0118/3720] Mention bash 3.1 as requirement on MinGW. Signed-off-by: Johannes Sixt --- README.MinGW | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.MinGW b/README.MinGW index bf3b4648a0..89b7065aac 100644 --- a/README.MinGW +++ b/README.MinGW @@ -23,6 +23,7 @@ In order to compile this code you need: mingw32-make-3.80.0-3.tar.gz unzip-5.51-1-bin.zip (this is not from MinGW, iirc) msysDTK-1.0.1.exe (contains ssh, perl) + bash-3.1-MSYS-1.0.11-snapshot.tar.bz2 - additional libraries: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz @@ -57,3 +58,11 @@ Caveats (aka bugs): implemented *very* simplistic: It just watches out for whitespace and double quote `"' characters. This may become a problem if you have exotic characters in your file names. + +- It seems that MSYS's default bash, 2.05b, has a bug that breaks git-am + (and, hence, git-rebase). If you see this error: + + Patch is empty. Was is split wrong? + + you need bash 3.1: Just unpack bash-3.1*.tar.bz2 and copy its bash.exe + over $MSYS/bin/sh.exe. From d17b18abecd04a8fcb4682c5ca5e5b851aa8e6ce Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 20 May 2007 21:25:49 +0200 Subject: [PATCH 0119/3720] Make mingw branch compile on Linux again --- Makefile | 4 ++-- git-compat-util.h | 22 ++++++++++++++-------- setup.c | 2 +- spawn-pipe.c | 5 ++++- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 1470f29a7d..a85f7102fc 100644 --- a/Makefile +++ b/Makefile @@ -209,8 +209,7 @@ SCRIPT_SH = \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ git-merge-resolve.sh git-merge-ours.sh \ - git-lost-found.sh git-quiltimport.sh \ - cpio.sh + git-lost-found.sh git-quiltimport.sh SCRIPT_PERL = \ git-add--interactive.perl \ @@ -504,6 +503,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) X = .exe NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ + SCRIPT_SH += cpio.sh endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease diff --git a/git-compat-util.h b/git-compat-util.h index f88f851941..7ae57d6019 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -48,16 +48,20 @@ #include #include #include -//#include #include -//#include -//#include -//#include +#ifndef __MINGW32__ +#include +#include +#include +#include +#endif #include #include -//#include -//#include -//#include +#ifndef __MINGW32__ +#include +#include +#include +#endif #ifndef NO_ETC_PASSWD #include #include @@ -345,7 +349,7 @@ static inline int strtoul_ui(char const *s, int base, unsigned int *result) return 0; } -// MinGW +#ifdef __MINGW32__ #ifndef S_ISLNK #define S_IFLNK 0120000 /* Symbolic link */ @@ -459,4 +463,6 @@ int mingw_socket(int domain, int type, int protocol); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +#endif /* __MINGW32__ */ + #endif diff --git a/setup.c b/setup.c index a66f479944..a2903b9573 100644 --- a/setup.c +++ b/setup.c @@ -78,11 +78,11 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; + char *p; #ifndef __MINGW32__ if (!pfx || !*pfx || arg[0] == '/') return arg; #else - char *p; /* don't add prefix to absolute paths */ const int is_absolute = is_dir_sep(arg[0]) || diff --git a/spawn-pipe.c b/spawn-pipe.c index 7d8aa7d6c7..c8f0452823 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -106,12 +106,15 @@ static char *path_lookup(const char *cmd, char **path) int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]) { +#ifdef __MINGW32__ char **path = get_path_split(); pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); free_path_split(path); - +#else + pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout); +#endif return pid; } From 312749fc466b79984901fbf94c890a388c597e97 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 22 May 2007 19:37:30 +0200 Subject: [PATCH 0120/3720] Fix 'make install' of the repository templates. In 2d84ffaf0da5f8ab0143b30cce254d7e6ea1e7a4 the path to the template directory was modified to be relative. However, since this setting is passed down to templates/Makefile, it installed the templates in the build directory. This works around the problem by not allowing the installation directory to be overridable. --- templates/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/Makefile b/templates/Makefile index a55edcc202..a4e7075caa 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -7,7 +7,7 @@ endif INSTALL ?= install TAR ?= tar prefix ?= $(HOME) -template_dir ?= $(prefix)/share/git-core/templates/ +template_dir = $(prefix)/share/git-core/templates/ # DESTDIR= # set NOEXECTEMPL to non-empty to change the names of hook scripts # so that the tools will not find them From a37c540e0efd1509127587faa6a201e338a0f016 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 22 May 2007 19:33:19 +0200 Subject: [PATCH 0121/3720] Avoid an error message due to the lack of the 'sync' command. --- git-repack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-repack.sh b/git-repack.sh index bf0bdcf4ff..acb78ba86b 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -99,7 +99,7 @@ then # We know $existing are all redundant. if [ -n "$existing" ] then - sync + sync 2> /dev/null ( cd "$PACKDIR" && for e in $existing do From ddb51d3baf427a9c38ae1d297eb07daae338536f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 22 May 2007 19:19:33 +0200 Subject: [PATCH 0122/3720] Make the progress indicator work when the total runtime is unknown. In order to allow progress indication when the total runtime is unknown, as well as if the total runtime is so long that the progress indicator stays at the same percentage for more than a second, an update of the indicator is forced every second. On Unix a time signal is received, which forces the update. On Windows we don't have signals. For this reason, a thread is spawned that forces the update every second. --- progress.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/progress.c b/progress.c index 05f7890314..7a8510542f 100644 --- a/progress.c +++ b/progress.c @@ -3,13 +3,26 @@ static volatile sig_atomic_t progress_update; +#ifndef __MINGW32__ static void progress_interval(int signum) { progress_update = 1; } +#else +static HANDLE progress_event; +static HANDLE progress_thread; + +static __stdcall unsigned heartbeat(void *dummy) +{ + while (WaitForSingleObject(progress_event, 1000) == WAIT_TIMEOUT) + progress_update = 1; + return 0; +} +#endif static void set_progress_signal(void) { +#ifndef __MINGW32__ struct sigaction sa; struct itimerval v; @@ -25,13 +38,43 @@ static void set_progress_signal(void) v.it_interval.tv_usec = 0; v.it_value = v.it_interval; setitimer(ITIMER_REAL, &v, NULL); +#else + /* this is just eye candy: errors are not fatal */ + progress_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (progress_event) { + progress_thread = (HANDLE) _beginthreadex(NULL, 0, heartbeat, NULL, 0, NULL); + if (!progress_thread ) + error("cannot create progress indicator"); + } else + error("cannot allocate resources for progress indicator"); +#endif } static void clear_progress_signal(void) { +#ifndef __MINGW32__ struct itimerval v = {{0,},}; setitimer(ITIMER_REAL, &v, NULL); signal(SIGALRM, SIG_IGN); +#else + /* this is just eye candy: errors are not fatal */ + if (progress_event) + SetEvent(progress_event); /* tells thread to terminate */ + if (progress_thread) { + int rc = WaitForSingleObject(progress_thread, 1000); + if (rc == WAIT_TIMEOUT) + error("progress thread did not terminate timely"); + else if (rc != WAIT_OBJECT_0) + error("waiting for progress thread failed: %lu", + GetLastError()); + CloseHandle(progress_thread); + } + if (progress_event) + CloseHandle(progress_event); + progress_event = NULL; + progress_thread = NULL; +#endif + progress_update = 0; } From eba4aff8fec97cbce3bb4ead1ed5e9857ebb95ef Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 09:40:43 +0200 Subject: [PATCH 0123/3720] Remove now unused dummy functions related to timer signal handling. --- compat/mingw.c | 13 ------------- git-compat-util.h | 13 ------------- 2 files changed, 26 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 14fabcbbc0..fa6f5f4504 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -51,19 +51,6 @@ int kill(pid_t pid, int sig) { return -1; } -int sigaction(int p1, const struct sigaction *p2, struct sigaction *p3) -{ - return -1; -} -int sigemptyset(sigset_t *p1) -{ - return -1; -} -int setitimer(int __which, const struct itimerval *__value, - struct itimerval *__ovalue) -{ - return -1; -} unsigned int sleep (unsigned int __seconds) { Sleep(__seconds*1000); diff --git a/git-compat-util.h b/git-compat-util.h index 7ae57d6019..515331d0b5 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -416,19 +416,6 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); #define POLLIN 1 #define POLLHUP 2 -typedef int siginfo_t; -struct sigaction { - void (*sa_handler)(int); - void (*sa_sigaction)(int, siginfo_t *, void *); - sigset_t sa_mask; - int sa_flags; - void (*sa_restorer)(void); -}; -#define SA_RESTART 0 -#define ITIMER_REAL 0 - -struct itimerval { struct timeval it_interval, it_value; }; - static inline int git_mkdir(const char *path, int mode) { return mkdir(path); From dafd0c5fece221379cf9f515e58c31dc1e44e339 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 10:54:08 +0200 Subject: [PATCH 0124/3720] Fix local clone on MinGW: absolute paths must use the drive letter. The default of pwd of MSYS's bash and /bin/pwd are to use /c/rest/of/path notation instead of c:/rest/of/path. But the former is not supported by programs that use the standard C runtime (instead of MinGW's own runtime). Hence, we must make sure that only drive letter notations are generated by using pwd's -W option. --- git-clone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 8e087a4793..1ff9f2987b 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -19,11 +19,11 @@ usage() { get_repo_base() { ( - cd "`/bin/pwd`" && + cd "`/bin/pwd -W`" && cd "$1" && { cd .git - pwd + pwd -W } ) 2>/dev/null } From afd5e6acb2f7adf6a3dd6049dabcafcd4458a92e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 22:26:41 +0200 Subject: [PATCH 0125/3720] Accept trailing slashes in lstat() implementation. lstat() is sometimes invoked with a path that ends in a slash (in particular, when dealing with subprojects). Windows's stat() does not accept such paths and fails with ENOENT. In this case we try again with a cleaned-up path. --- compat/mingw.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index fa6f5f4504..ac8b8e0414 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -25,7 +25,27 @@ int fchmod(int fildes, mode_t mode) int lstat(const char *file_name, struct stat *buf) { - return stat(file_name, buf); + int namelen; + static char alt_name[PATH_MAX]; + + if (!stat(file_name, buf)) + return 0; + + /* if file_name ended in a '/', Windows returned ENOENT; + * try again without trailing slashes + */ + if (errno != ENOENT) + return -1; + namelen = strlen(file_name); + if (namelen && file_name[namelen-1] != '/') + return -1; + while (namelen && file_name[namelen-1] == '/') + --namelen; + if (!namelen || namelen >= PATH_MAX) + return -1; + memcpy(alt_name, file_name, namelen); + alt_name[namelen] = 0; + return stat(alt_name, buf); } /* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ From 4694606a42710234433aec3cedfe7cad3d387e25 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 22:28:41 +0200 Subject: [PATCH 0126/3720] Check TMP and TEMP environment variables in addition to TMPDIR. Windows uses TMP and TEMP, but we still check for TMPDIR, which some scripts may set. --- path.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/path.c b/path.c index ced3a7c586..29570ee52a 100644 --- a/path.c +++ b/path.c @@ -73,7 +73,10 @@ int git_mkstemp(char *path, size_t len, const char *template) { char *env, *pch = path; - if ((env = getenv("TMPDIR")) == NULL) { + if ((env = getenv("TMPDIR")) == NULL && + /* on Windows it is TMP and TEMP */ + (env = getenv("TMP")) == NULL && + (env = getenv("TEMP")) == NULL) { strcpy(pch, "/tmp/"); len -= 5; pch += 5; From 782c4e20196386eafa1dd0d29d09c78ecbc0fbb8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 22:31:11 +0200 Subject: [PATCH 0127/3720] Skip a test dealing with symbolic links. --- t/t4122-apply-symlink-inside.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh index 3ddfe64b02..9af8bcc9f6 100755 --- a/t/t4122-apply-symlink-inside.sh +++ b/t/t4122-apply-symlink-inside.sh @@ -3,6 +3,13 @@ test_description='apply to deeper directory without getting fooled with symlink' . ./test-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + lecho () { for l_ do From d681388621ce2e32ec1275a9edfea59bb0a4a0cb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 16:02:21 +0200 Subject: [PATCH 0128/3720] Avoid double-slash in path names that depend on $(sharedir). Recent git-gui has the ability to determine the location of its library files relative to the --exec-dir. Its Makefile enables this capability depending on the install paths that are specified. However, without this fix there is an extra slash in a path specification, so that the Makefile does not recognize the equivalence of two paths that it compares. As a side-effect, this avoids an ugly compiled-in double-slash in $(template_dir). Signed-off-by: Johannes Sixt --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1ed09aca00..9592ab7f05 100644 --- a/Makefile +++ b/Makefile @@ -144,7 +144,7 @@ STRIP ?= strip prefix = $(HOME) bindir = $(prefix)/bin gitexecdir = $(bindir) -sharedir = $(prefix)/share/ +sharedir = $(prefix)/share template_dir = $(sharedir)/git-core/templates/ ifeq ($(prefix),/usr) sysconfdir = /etc From 77398b214dc6c9c1ffd169cae821b31405c0cfc7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 19:53:05 +0200 Subject: [PATCH 0129/3720] Introduce git_etc_gitconfig() that encapsulates access of ETC_GITCONFIG. In a subsequent patch the path to the system-wide config file will be computed. This is a preparation for that change. It turns all accesses of ETC_GITCONFIG into function calls. There is no change in behavior. As a consequence, config.c is the only file that needs the definition of ETC_GITCONFIG. Hence, -DETC_GITCONFIG is removed from the CFLAGS and a special build rule for config.c is introduced. As a side-effect, changing the defintion of ETC_GITCONFIG (e.g. in config.mak) does not trigger a complete rebuild anymore. Signed-off-by: Johannes Sixt --- Makefile | 5 ++++- builtin-config.c | 4 ++-- cache.h | 1 + config.c | 10 ++++++++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 9592ab7f05..2b0e5ce536 100644 --- a/Makefile +++ b/Makefile @@ -731,7 +731,7 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) LIBS = $(GITLIBS) $(EXTLIBS) BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ - -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $(COMPAT_CFLAGS) + $(COMPAT_CFLAGS) LIB_OBJS += $(COMPAT_OBJS) ALL_CFLAGS += $(BASIC_CFLAGS) @@ -878,6 +878,9 @@ exec_cmd.o: exec_cmd.c GIT-CFLAGS builtin-init-db.o: builtin-init-db.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< +config.o: config.c GIT-CFLAGS + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $< + http.o: http.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $< diff --git a/builtin-config.c b/builtin-config.c index b2515f7e65..54c9885c32 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -74,7 +74,7 @@ static int get_value(const char* key_, const char* regex_) local = repo_config = xstrdup(git_path("config")); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); - system_wide = ETC_GITCONFIG; + system_wide = git_etc_gitconfig(); } key = xstrdup(key_); @@ -154,7 +154,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } } else if (!strcmp(argv[1], "--system")) - setenv("GIT_CONFIG", ETC_GITCONFIG, 1); + setenv("GIT_CONFIG", git_etc_gitconfig(), 1); else if (!strcmp(argv[1], "--rename-section")) { int ret; if (argc != 4) diff --git a/cache.h b/cache.h index a5c8b717dc..6a8534e0aa 100644 --- a/cache.h +++ b/cache.h @@ -507,6 +507,7 @@ 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 const char *git_etc_gitconfig(void); 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 36e76da493..79c32a0338 100644 --- a/config.c +++ b/config.c @@ -6,6 +6,7 @@ * */ #include "cache.h" +#include "exec_cmd.h" #define MAXNAME (256) @@ -392,6 +393,11 @@ int git_config_from_file(config_fn_t fn, const char *filename) return ret; } +const char *git_etc_gitconfig(void) +{ + return ETC_GITCONFIG; +} + int git_config(config_fn_t fn) { int ret = 0; @@ -404,8 +410,8 @@ int git_config(config_fn_t fn) * config file otherwise. */ filename = getenv(CONFIG_ENVIRONMENT); if (!filename) { - if (!access(ETC_GITCONFIG, R_OK)) - ret += git_config_from_file(fn, ETC_GITCONFIG); + if (!access(git_etc_gitconfig(), R_OK)) + ret += git_config_from_file(fn, git_etc_gitconfig()); home = getenv("HOME"); filename = getenv(CONFIG_LOCAL_ENVIRONMENT); if (!filename) From 44bacc53bf8d5e0e7f526f6599ec0b9a9836ebc2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 20:14:53 +0200 Subject: [PATCH 0130/3720] Allow ETC_GITCONFIG to be a relative path. If ETC_GITCONFIG is not an absolute path, interpret it relative to --exec-dir. This makes the installed binaries relocatable because the prefix is not compiled-in. Signed-off-by: Johannes Sixt --- config.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/config.c b/config.c index 79c32a0338..1c87e8e3f9 100644 --- a/config.c +++ b/config.c @@ -395,7 +395,17 @@ int git_config_from_file(config_fn_t fn, const char *filename) const char *git_etc_gitconfig(void) { - return ETC_GITCONFIG; + static const char *system_wide; + if (!system_wide) { + system_wide = ETC_GITCONFIG; + /* interpret path relative to exec-dir */ + if (system_wide[0] != '/' && system_wide[1] != ':') { + const char *exec_path = git_exec_path(); + system_wide = prefix_path(exec_path, strlen(exec_path), + system_wide); + } + } + return system_wide; } int git_config(config_fn_t fn) From 2a51de45cfc1270492d757b3bc14943a71ab6232 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 20:17:10 +0200 Subject: [PATCH 0131/3720] On MinGW the system-wide config file is a relative path. This is necessary because if the toolset is provided as a setup file, it is customary that the user can choose any location to install to. Signed-off-by: Johannes Sixt --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 2b0e5ce536..48fa6a1af2 100644 --- a/Makefile +++ b/Makefile @@ -503,6 +503,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) X = .exe NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ + ETC_GITCONFIG = ../etc/gitconfig SCRIPT_SH += cpio.sh endif ifneq (,$(findstring arm,$(uname_M))) From 16c1568546fcb0ba04409d7b32326d66812e63c3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 20:18:28 +0200 Subject: [PATCH 0132/3720] Silence a warning about an undeclared git_exec_path(). Pull in its declaration. Signed-off-by: Johannes Sixt --- builtin-init-db.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-init-db.c b/builtin-init-db.c index ecf3db954a..0268ad2905 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -5,6 +5,7 @@ */ #include "cache.h" #include "builtin.h" +#include "exec_cmd.h" #ifndef DEFAULT_GIT_TEMPLATE_DIR #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/" From 24d0e15093c5e1814b28809814579e8c11f89588 Mon Sep 17 00:00:00 2001 From: Mark Levedahl Date: Mon, 25 Jun 2007 22:43:19 -0400 Subject: [PATCH 0133/3720] gitk - Make selection highlight color configurable Cygwin's tk by default uses a very dark selection background color that makes the currently selected text almost unreadable. On linux, the default selection background is a light gray which is very usable. This makes the default a light gray everywhere but allows the user to configure the color as well. Signed-off-by: Mark Levedahl --- gitk | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index c09ee9a5e5..b044914c1f 100755 --- a/gitk +++ b/gitk @@ -402,7 +402,7 @@ proc makewindow {} { global rowctxmenu mergemax wrapcomment global highlight_files gdttype global searchstring sstring - global bgcolor fgcolor bglist fglist diffcolors + global bgcolor fgcolor bglist fglist diffcolors selectbgcolor global headctxmenu menu .bar @@ -457,15 +457,18 @@ proc makewindow {} { set cscroll .tf.histframe.csb set canv .tf.histframe.pwclist.canv canvas $canv \ + -selectbackground $selectbgcolor \ -background $bgcolor -bd 0 \ -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll" .tf.histframe.pwclist add $canv set canv2 .tf.histframe.pwclist.canv2 canvas $canv2 \ + -selectbackground $selectbgcolor \ -background $bgcolor -bd 0 -yscrollincr $linespc .tf.histframe.pwclist add $canv2 set canv3 .tf.histframe.pwclist.canv3 canvas $canv3 \ + -selectbackground $selectbgcolor \ -background $bgcolor -bd 0 -yscrollincr $linespc .tf.histframe.pwclist add $canv3 eval .tf.histframe.pwclist sash place 0 $geometry(pwsash0) @@ -666,6 +669,7 @@ proc makewindow {} { set cflist .bright.cfiles set indent [font measure $mainfont "nn"] text $cflist \ + -selectbackground $selectbgcolor \ -background $bgcolor -foreground $fgcolor \ -font $mainfont \ -tabs [list $indent [expr {2 * $indent}]] \ @@ -825,7 +829,7 @@ proc savestuff {w} { global maxwidth showneartags global viewname viewfiles viewargs viewperm nextviewnum global cmitmode wrapcomment - global colors bgcolor fgcolor diffcolors + global colors bgcolor fgcolor diffcolors selectbgcolor if {$stuffsaved} return if {![winfo viewable .]} return @@ -844,6 +848,7 @@ proc savestuff {w} { puts $f [list set fgcolor $fgcolor] puts $f [list set colors $colors] puts $f [list set diffcolors $diffcolors] + puts $f [list set selectbgcolor $selectbgcolor] puts $f "set geometry(main) [wm geometry .]" puts $f "set geometry(topwidth) [winfo width .tf]" @@ -5846,7 +5851,7 @@ proc doquit {} { proc doprefs {} { global maxwidth maxgraphpct diffopts global oldprefs prefstop showneartags - global bgcolor fgcolor ctext diffcolors + global bgcolor fgcolor ctext diffcolors selectbgcolor global uifont set top .gitkprefs @@ -5913,6 +5918,10 @@ proc doprefs {} { "diff hunk header" \ [list $ctext tag conf hunksep -foreground]] grid x $top.hunksepbut $top.hunksep -sticky w + label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor + button $top.selbgbut -text "Select bg" -font optionfont \ + -command [list choosecolor selectbgcolor 0 $top.selbgsep background setselbg] + grid x $top.selbgbut $top.selbgsep -sticky w frame $top.buts button $top.buts.ok -text "OK" -command prefsok -default active @@ -5937,6 +5946,16 @@ proc choosecolor {v vi w x cmd} { eval $cmd $c } +proc setselbg {c} { + global bglist cflist + foreach w $bglist { + $w configure -selectbackground $c + } + $cflist tag configure highlight \ + -background [$cflist cget -selectbackground] + allcanvs itemconf secsel -fill $c +} + proc setbg {c} { global bglist @@ -6293,6 +6312,7 @@ set colors {green red blue magenta darkgrey brown orange} set bgcolor white set fgcolor black set diffcolors {red "#00a000" blue} +set selectbgcolor gray85 catch {source ~/.gitk} From 568785d5b13cdf06bd81b8e161a5405596f44197 Mon Sep 17 00:00:00 2001 From: Mark Levedahl Date: Mon, 25 Jun 2007 22:43:20 -0400 Subject: [PATCH 0134/3720] gitk - Update fontsize in patch / tree list When adjusting fontsize (using ctrl+/-), all panes except the lower right were updated. This fixes that. Signed-off-by: Mark Levedahl --- gitk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitk b/gitk index b044914c1f..a7139b4033 100755 --- a/gitk +++ b/gitk @@ -4696,13 +4696,14 @@ proc redisplay {} { } proc incrfont {inc} { - global mainfont textfont ctext canv phase + global mainfont textfont ctext canv phase cflist global stopped entries unmarkmatches set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]] set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]] setcoords $ctext conf -font $textfont + $cflist conf -font $textfont $ctext tag conf filesep -font [concat $textfont bold] foreach e $entries { $e conf -font $mainfont From 5eecfa3becc25a6bf5bfc7e3657d77a40cbdd60a Mon Sep 17 00:00:00 2001 From: Mark Levedahl Date: Mon, 25 Jun 2007 22:43:21 -0400 Subject: [PATCH 0135/3720] gitk - Allow specifying tabstop as other than default 8 characters. Not all projects use the convention that one tabstop = 8 characters, and a common convention is to use one tabstop = on level of indent. For such projects, using 8 characters per tabstop often shows too much whitespace per indent. This allows the user to configure the number of characters to use per tabstop. Signed-off-by: Mark Levedahl --- gitk | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/gitk b/gitk index a7139b4033..1c9c9ccc78 100755 --- a/gitk +++ b/gitk @@ -395,7 +395,7 @@ proc confirm_popup msg { proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist - global textfont mainfont uifont + global textfont mainfont uifont tabstop global findtype findtypemenu findloc findstring fstring geometry global entries sha1entry sha1string sha1but global maincursor textcursor curtextcursor @@ -615,6 +615,7 @@ proc makewindow {} { pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left set ctext .bleft.ctext text $ctext -background $bgcolor -foreground $fgcolor \ + -tabs "[expr {$tabstop * $charspc}]" \ -state disabled -font $textfont \ -yscrollcommand scrolltext -wrap none scrollbar .bleft.sb -command "$ctext yview" @@ -824,7 +825,7 @@ proc click {w} { } proc savestuff {w} { - global canv canv2 canv3 ctext cflist mainfont textfont uifont + global canv canv2 canv3 ctext cflist mainfont textfont uifont tabstop global stuffsaved findmergefiles maxgraphpct global maxwidth showneartags global viewname viewfiles viewargs viewperm nextviewnum @@ -838,6 +839,7 @@ proc savestuff {w} { puts $f [list set mainfont $mainfont] puts $f [list set textfont $textfont] puts $f [list set uifont $uifont] + puts $f [list set tabstop $tabstop] puts $f [list set findmergefiles $findmergefiles] puts $f [list set maxgraphpct $maxgraphpct] puts $f [list set maxwidth $maxwidth] @@ -4697,12 +4699,13 @@ proc redisplay {} { proc incrfont {inc} { global mainfont textfont ctext canv phase cflist + global charspc tabstop global stopped entries unmarkmatches set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]] set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]] setcoords - $ctext conf -font $textfont + $ctext conf -font $textfont -tabs "[expr {$tabstop * $charspc}]" $cflist conf -font $textfont $ctext tag conf filesep -font [concat $textfont bold] foreach e $entries { @@ -5853,7 +5856,7 @@ proc doprefs {} { global maxwidth maxgraphpct diffopts global oldprefs prefstop showneartags global bgcolor fgcolor ctext diffcolors selectbgcolor - global uifont + global uifont tabstop set top .gitkprefs set prefstop $top @@ -5891,6 +5894,9 @@ proc doprefs {} { checkbutton $top.ntag.b -variable showneartags pack $top.ntag.b $top.ntag.l -side left grid x $top.ntag -sticky w + label $top.tabstopl -text "tabstop" -font optionfont + spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop + grid x $top.tabstopl $top.tabstop -sticky w label $top.cdisp -text "Colors: press to choose" $top.cdisp configure -font $uifont @@ -5989,9 +5995,11 @@ proc prefscan {} { proc prefsok {} { global maxwidth maxgraphpct global oldprefs prefstop showneartags + global charspc ctext tabstop catch {destroy $prefstop} unset prefstop + $ctext configure -tabs "[expr {$tabstop * $charspc}]" if {$maxwidth != $oldprefs(maxwidth) || $maxgraphpct != $oldprefs(maxgraphpct)} { redisplay @@ -6297,6 +6305,7 @@ if {$tclencoding == {}} { set mainfont {Helvetica 9} set textfont {Courier 9} set uifont {Helvetica 9 bold} +set tabstop 8 set findmergefiles 0 set maxgraphpct 50 set maxwidth 16 From 28edb31439f680718bd678a85ee4e805aa33c0d1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Jun 2007 09:07:17 +0200 Subject: [PATCH 0136/3720] Revert "Better contrast of text and background of selected lines." This reverts commit 3724812944c65714216ecdb87835835cf12f8870. We have now a better solution by Mark Levedahl, where the highlight color can be configured. --- gitk | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gitk b/gitk index 1c9c9ccc78..513fc2b8c9 100755 --- a/gitk +++ b/gitk @@ -683,7 +683,7 @@ proc makewindow {} { pack .bright.sb -side right -fill y pack $cflist -side left -fill both -expand 1 $cflist tag configure highlight \ - -background [$cflist cget -highlightbackground] + -background [$cflist cget -selectbackground] $cflist tag configure bold -font [concat $mainfont bold] .pwbottom add .bright @@ -1790,7 +1790,7 @@ proc bolden {row font} { $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($row)] \ -outline {{}} -tags secsel \ - -fill [$canv cget -highlightbackground]] + -fill [$canv cget -selectbackground]] $canv lower $t } } @@ -1804,7 +1804,7 @@ proc bolden_name {row font} { $canv2 delete secsel set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \ -outline {{}} -tags secsel \ - -fill [$canv2 cget -highlightbackground]] + -fill [$canv2 cget -selectbackground]] $canv2 lower $t } } @@ -3920,15 +3920,15 @@ proc selectline {l isnew} { if {![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ - -tags secsel -fill [$canv cget -highlightbackground]] + -tags secsel -fill [$canv cget -selectbackground]] $canv lower $t $canv2 delete secsel set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \ - -tags secsel -fill [$canv2 cget -highlightbackground]] + -tags secsel -fill [$canv2 cget -selectbackground]] $canv2 lower $t $canv3 delete secsel set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \ - -tags secsel -fill [$canv3 cget -highlightbackground]] + -tags secsel -fill [$canv3 cget -selectbackground]] $canv3 lower $t if {$isnew} { From 3ada7967dca3d26f88efcf23dfb7317e1ff603a1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 13 Jul 2007 09:27:40 +0200 Subject: [PATCH 0137/3720] Disable the new test, which covers only symbolic links. --- t/t2007-checkout-symlink.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t2007-checkout-symlink.sh b/t/t2007-checkout-symlink.sh index 0526fce163..0bf1ddb94b 100755 --- a/t/t2007-checkout-symlink.sh +++ b/t/t2007-checkout-symlink.sh @@ -6,6 +6,13 @@ test_description='git checkout to switch between branches with symlink<->dir' . ./test-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success setup ' mkdir frotz && From 91dd11cb86bed99c4d8332f34cb091946610d5f0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 21 Jul 2007 16:03:46 +0200 Subject: [PATCH 0138/3720] Disarm .dir and .env support on MinGW. We do not yet support changing the directory of the spawned process (it would require a getwd(), chdir(new), chdir(back) sequence). Even though we can remove environment variables in the spawned process, we cannot yet add new ones. --- run-command.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/run-command.c b/run-command.c index d42aa1074e..5964e7d4dd 100644 --- a/run-command.c +++ b/run-command.c @@ -14,6 +14,7 @@ int start_command(struct child_process *cmd) int need_in, need_out; int fdin[2] = { -1, -1 }; int fdout[2] = { -1, -1 }; + char **env = environ; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { @@ -55,21 +56,26 @@ int start_command(struct child_process *cmd) fdout[1] = cmd->out; } + if (cmd->dir) + die("chdir in start_command() not implemented"); if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { + if (cmd->git_cmd) + die("modifying environment for git_cmd in start_command() not implemented"); + env = copy_environ(); for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - putenv((char*)*cmd->env); + die("setting environment in start_command() not implemented"); else - unsetenv(*cmd->env); + env_unsetenv(env, *cmd->env); } } if (cmd->git_cmd) { cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout); } else { - cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, environ, fdin, fdout); + cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout); } } if (cmd->pid < 0) { From cef2e2635135ba148e853cacc9076e3595808b73 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 21 Jul 2007 23:16:20 +0200 Subject: [PATCH 0139/3720] Add a fake S_ISSOCK() macro --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index dfaf5fff31..ddafec997f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -375,6 +375,7 @@ static inline int strtoul_ui(char const *s, int base, unsigned int *result) #ifndef S_ISLNK #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(x) 0 #endif #ifndef S_ISGRP From 2e435b2b21dce07ecd0ee12e148fd8b00345d228 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 21 Jul 2007 23:18:41 +0200 Subject: [PATCH 0140/3720] Skip tests involving symbolic links. --- t/t3700-add.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t3700-add.sh b/t/t3700-add.sh index b52fde8577..b216a3ae88 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -30,6 +30,7 @@ test_expect_success \ *) echo fail; git ls-files --stage xfoo1; (exit 1);; esac' +test "$no_symlinks" || { test_expect_success 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo1 && ln -s foo xfoo1 && @@ -39,6 +40,7 @@ test_expect_success 'git add: filemode=0 should not get confused by symlink' ' *) echo fail; git ls-files --stage xfoo1; (exit 1);; esac ' +} test_expect_success \ 'git update-index --add: Test that executable bit is not used...' \ @@ -51,6 +53,7 @@ test_expect_success \ *) echo fail; git ls-files --stage xfoo2; (exit 1);; esac' +test "$no_symlinks" || { test_expect_success 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo2 && ln -s foo xfoo2 && @@ -70,6 +73,7 @@ test_expect_success \ 120000" "*xfoo3) echo ok;; *) echo fail; git ls-files --stage xfoo3; (exit 1);; esac' +} test_expect_success '.gitignore test setup' ' echo "*.ig" >.gitignore && From 0c344bc22906f0e166f01c1b2075ecfba7dac40f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:11:54 +0200 Subject: [PATCH 0141/3720] Skip some git diff tests if the file system does not support funny names. Signed-off-by: Johannes Sixt --- t/t3902-quoted.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh index 63f950b179..e8ad85afe4 100755 --- a/t/t3902-quoted.sh +++ b/t/t3902-quoted.sh @@ -14,6 +14,13 @@ LF=' ' DQ='"' +echo foo > "Name and an${HT}HT" +test -f "Name and an${HT}HT" || { + # since FAT/NTFS does not allow tabs in filenames, skip this test + say 'Your filesystem does not allow tabs in filenames, test skipped.' + test_done +} + for_each_name () { for name in \ Name "Name and a${LF}LF" "Name and an${HT}HT" "Name${DQ}" \ From 5c52dc4bf0d53c75b473fa60ffafa4e2e961dc55 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:18:36 +0200 Subject: [PATCH 0142/3720] update-server-info is not supported on MinGW. Skip tests. --- t/t1301-shared-repo.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index bb5f30220a..3bf78ae619 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -14,6 +14,10 @@ test_expect_success 'shared=all' ' test 2 = $(git config core.sharedrepository) ' +say "update-server-info not supported - skipping tests" +test_done +exit 0 + test_expect_success 'update-server-info honors core.sharedRepository' ' : > a1 && git add a1 && From f0ec63a99a4925804eecd69c792e0ee600871b73 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 20:37:42 +0200 Subject: [PATCH 0143/3720] Install 'core.symlinks false' under MinGW. --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 760b5448be..47b1fdc326 100644 --- a/Makefile +++ b/Makefile @@ -722,6 +722,7 @@ bindir_SQ = $(subst ','\'',$(bindir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) template_dir_SQ = $(subst ','\'',$(template_dir)) prefix_SQ = $(subst ','\'',$(prefix)) +sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) @@ -1001,8 +1002,11 @@ remove-dashes: install: all $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(sysconfdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)' + GIT_CONFIG='$(DESTDIR_SQ)$(sysconfdir_SQ)/gitconfig' \ + $(DESTDIR_SQ)$(bindir_SQ)/git-config$X core.symlinks false $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' install ifndef NO_TCLTK From 631f6e62498bb0439be2718c04a4f5e76baaeec0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 12 Jan 2007 16:41:22 +0100 Subject: [PATCH 0144/3720] Fake reencoding success under NO_ICONV instead of returning NULL. git-am when invoked from git-rebase seems to rely on successful conversion. --- utf8.c | 7 +++++++ utf8.h | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/utf8.c b/utf8.c index 4efef6faf7..5949b4d2d4 100644 --- a/utf8.c +++ b/utf8.c @@ -353,4 +353,11 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e iconv_close(conv); return out; } +#else +char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding) +{ + if (!in_encoding) + return NULL; + return xstrdup(in); +} #endif diff --git a/utf8.h b/utf8.h index 15db6f1f27..a8b8c2f4da 100644 --- a/utf8.h +++ b/utf8.h @@ -7,10 +7,6 @@ int is_encoding_utf8(const char *name); int print_wrapped_text(const char *text, int indent, int indent2, int len); -#ifndef NO_ICONV char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding); -#else -#define reencode_string(a,b,c) NULL -#endif #endif From f5f46bfe24411ce8b4955df4cc5b2e0d78f0a0c5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 21 Jul 2007 23:21:54 +0200 Subject: [PATCH 0145/3720] Work around a CR being written by git-tag if it is redirected to a file. Where the heck does this come from? A useless use of cat helps. --- t/t7004-tag.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 17de2a90e6..99b417ada5 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -108,9 +108,9 @@ mytag EOF test_expect_success \ 'trying to delete tags without params should succeed and do nothing' ' - git tag -l > actual && git diff expect actual && + git tag -l | cat > actual && git diff expect actual && git-tag -d && - git tag -l > actual && git diff expect actual + git tag -l | cat > actual && git diff expect actual ' test_expect_success \ @@ -164,7 +164,7 @@ test_expect_success 'listing all tags should print them ordered' ' git tag a1 && git tag v1.0 && git tag t210 && - git tag -l > actual && + git tag -l | cat > actual && git diff expect actual ' From 64e9bd1483cea1fee0dd1b76ee988e20a0b997fb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:19:06 +0200 Subject: [PATCH 0146/3720] Skip some tests that depend on technology that we have not dealt with. --- t/t3900-i18n-commit.sh | 4 ++++ t/t3901-i18n-patch.sh | 4 ++++ t/t4121-apply-diffs.sh | 2 ++ t/t5100-mailinfo.sh | 4 ++++ t/t5302-pack-index.sh | 2 ++ t/t5502-quickfetch.sh | 3 +++ t/t6023-merge-file.sh | 3 +++ t/t7003-filter-branch.sh | 3 +++ t/t9001-send-email.sh | 4 ++++ t/t9200-git-cvsexportcommit.sh | 4 ++++ t/t9300-fast-import.sh | 4 ++++ 11 files changed, 37 insertions(+) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index fcbabe8ec3..4886d9f37b 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -7,6 +7,10 @@ test_description='commit and log output encodings' . ./test-lib.sh +say "iconv not supported, skipping tests." +test_done +exit 0 + compare_with () { git show -s $1 | sed -e '1,/^$/d' -e 's/^ //' -e '$d' >current && git diff current "$2" diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index 28e9e372f3..41e0d42c62 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -7,6 +7,10 @@ test_description='i18n settings and format-patch | am pipe' . ./test-lib.sh +say "iconv not supported, skipping tests." +test_done +exit 0 + check_encoding () { # Make sure characters are not corrupted cnt="$1" header="$2" i=1 j=0 bad=0 diff --git a/t/t4121-apply-diffs.sh b/t/t4121-apply-diffs.sh index aff551a1d7..d93b61d8c4 100755 --- a/t/t4121-apply-diffs.sh +++ b/t/t4121-apply-diffs.sh @@ -3,6 +3,8 @@ test_description='git apply for contextually independent diffs' . ./test-lib.sh +test_done + echo '1 2 3 diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 9b1a74542a..0dcab1fbfe 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -7,6 +7,10 @@ test_description='git mailinfo and git mailsplit test' . ./test-lib.sh +say "git-mailinfo does not work yet; skipping tests." +test_done +exit 0 + test_expect_success 'split sample box' \ 'git mailsplit -o. ../t5100/sample.mbox >last && last=`cat last` && diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 4f58c4c3f9..06b2f38d75 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -59,6 +59,7 @@ test_expect_success \ 'cmp "test-1-${pack1}.idx" "1.idx" && cmp "test-2-${pack2}.idx" "2.idx"' +false && { test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 merge.err && grep "Cannot merge binary files" merge.err diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 4ddd656e84..7ec74172ae 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -3,6 +3,9 @@ test_description='git-filter-branch' . ./test-lib.sh +say "filter-branch has not been taken care of - skipping tests" +test_done + make_commit () { lower=$(echo $1 | tr A-Z a-z) echo $lower > $lower diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index e9ea33c18d..d58fccb522 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -3,6 +3,10 @@ test_description='git-send-email' . ./test-lib.sh +say "cannot invoke fake.sendmail; skipping test" +test_done +exit 0 + PROG='git send-email' test_expect_success \ 'prepare reference tree' \ diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 8e5722245d..f7936e87da 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -6,6 +6,10 @@ test_description='CVS export comit. ' . ./test-lib.sh +say "CVS does not work on MinGW, skipping tests." +test_done +exit 0 + cvs >/dev/null 2>&1 if test $? -ne 1 then diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 4b920be331..902b5f5f7f 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -7,6 +7,10 @@ test_description='test git-fast-import utility' . ./test-lib.sh . ../diff-lib.sh ;# test-lib chdir's into trash +say "git-fast-import has not been taken care of, skipping test." +test_done +exit 0 + file2_data='file2 second line of EOF' From c10900175c37827e1c53a30e07df843b4ac94a8c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:17:16 +0200 Subject: [PATCH 0147/3720] Work around failures due to bogus quoting of ^ and {}. --- t/t3404-rebase-interactive.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 43a6675caa..48dc6d6b41 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -150,7 +150,7 @@ test_expect_success 'retain authorship' ' test_tick && GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && git tag twerp && - git rebase -i --onto master HEAD^ && + git rebase -i --onto master HEAD~1 && git show HEAD | grep "^Author: Twerp Snog" ' @@ -194,7 +194,7 @@ test_expect_success 'preserve merges with -p' ' test_expect_success '--continue tries to commit' ' test_tick && - ! git rebase -i --onto new-branch1 HEAD^ && + ! git rebase -i --onto new-branch1 HEAD~1 && echo resolved > file1 && git add file1 && FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue && @@ -203,9 +203,9 @@ test_expect_success '--continue tries to commit' ' ' test_expect_success 'verbose flag is heeded, even after --continue' ' - git reset --hard HEAD@{1} && + git reset --hard $(git rev-parse HEAD@{1}) && test_tick && - ! git rebase -v -i --onto new-branch1 HEAD^ && + ! git rebase -v -i --onto new-branch1 HEAD~1 && echo resolved > file1 && git add file1 && git rebase --continue > output && From 382210f715c0e1ef7a19eb10977dae4265a2c88f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 15:53:54 +0100 Subject: [PATCH 0148/3720] Remove the symbolic link to simplify bootstrapping this version. The MinGW port does have partial support for symbolic links now. But in order to allow others who still do not have this version to use their old version on Windows to pull and checkout this version we better drop the symbolic link. --- RelNotes | 1 - 1 file changed, 1 deletion(-) delete mode 120000 RelNotes diff --git a/RelNotes b/RelNotes deleted file mode 120000 index 1f6c16e1dc..0000000000 --- a/RelNotes +++ /dev/null @@ -1 +0,0 @@ -Documentation/RelNotes-1.5.2.4.txt \ No newline at end of file From daf422895c9b00255b5e79be5c1c30bdebcb19a9 Mon Sep 17 00:00:00 2001 From: Nguyen Thai Ngoc Duy Date: Tue, 31 Jul 2007 11:09:48 -0400 Subject: [PATCH 0149/3720] Mention libiconv as a requirement for git-am --- README.MinGW | 1 + 1 file changed, 1 insertion(+) diff --git a/README.MinGW b/README.MinGW index 89b7065aac..c0b8f66b93 100644 --- a/README.MinGW +++ b/README.MinGW @@ -28,6 +28,7 @@ In order to compile this code you need: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz tcltk-8.4.1-1.exe (for gitk, git-gui) + libiconv-1.9.2-1-{lib,bin}.zip (for git-am, from http://gnuwin32.sourceforge.net/packages/libiconv.htm) STATUS From 2e2f5df3c1433a6f1bd6943dbec1b0b631759499 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 6 Aug 2007 21:39:06 +0200 Subject: [PATCH 0150/3720] Link with libiconv (1.9.2). --- Makefile | 3 ++- README.MinGW | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 760b5448be..f45f0e6179 100644 --- a/Makefile +++ b/Makefile @@ -482,7 +482,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_UNSETENV=YesPlease NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease - NO_ICONV=YesPlease + NEEDS_LIBICONV = YesPlease + OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease NO_SYMLINKS=YesPlease diff --git a/README.MinGW b/README.MinGW index c0b8f66b93..436d7b7849 100644 --- a/README.MinGW +++ b/README.MinGW @@ -28,7 +28,8 @@ In order to compile this code you need: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz tcltk-8.4.1-1.exe (for gitk, git-gui) - libiconv-1.9.2-1-{lib,bin}.zip (for git-am, from http://gnuwin32.sourceforge.net/packages/libiconv.htm) + libiconv-1.9.2-1-{lib,bin,lib}.zip (for git-am, + from http://gnuwin32.sourceforge.net/packages/libiconv.htm) STATUS From 2d5d2c84f18762a50ddc843b560b2b0b53ee1426 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 22:54:41 +0100 Subject: [PATCH 0151/3720] Fix inifinite loop In setup_git_directory_gently(), there is a hack to allow for stopping the search at the drive letter. Only that the patch was incomplete; we really have to stop there, instead of looping infinitely. Signed-off-by: Johannes Schindelin --- setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.c b/setup.c index a1aa5a3076..e921013926 100644 --- a/setup.c +++ b/setup.c @@ -260,7 +260,7 @@ const char *setup_git_directory_gently(int *nongit_ok) for (;;) { if (is_git_directory(".git")) break; - if (offset == 0) { + if (offset == minoffset) { offset = -1; break; } From bf788d7e65eeaebb65ddb330c32aac0d7bd5e325 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 22:31:42 +0100 Subject: [PATCH 0152/3720] Makefile: be nice when running in a path containing spaces Without this patch, GIT-VERSION-GEN is not able to run. Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 47b1fdc326..d42734aeef 100644 --- a/Makefile +++ b/Makefile @@ -124,7 +124,7 @@ all: # GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE - @$(SHELL_PATH) ./GIT-VERSION-GEN + @"$(SHELL_PATH)" ./GIT-VERSION-GEN -include GIT-VERSION-FILE uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') From 70cff4144391c83bdac5c98c99642d29181aa67a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 23:01:57 +0100 Subject: [PATCH 0153/3720] Fix some compiler settings/paths for MinGW It seems that you have to jump through hoops to make trivial things such as "install.exe" do the right thing on Windows... Also, it seems that Windows Vista deliberately broke "access()". Apparently, they used that name in their runtime, but that function does something completely different than POSIX access(). So define __USE_MINGW_ACCESS to work around that. Signed-off-by: Johannes Schindelin --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d42734aeef..85df9a5c67 100644 --- a/Makefile +++ b/Makefile @@ -176,7 +176,7 @@ CC = gcc AR = ar RM = rm -f TAR = tar -INSTALL = install +INSTALL = /bin/install RPMBUILD = rpmbuild TCL_PATH = tclsh TCLTK_PATH = wish @@ -373,7 +373,7 @@ BUILTIN_OBJS = \ builtin-pack-refs.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) -EXTLIBS = -lz +EXTLIBS = /mingw/lib/libz.a # # Platform specific tweaks @@ -488,7 +488,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe From 7999f434d70dd1c4849c874d1767b24fb77a33df Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 23:12:03 +0100 Subject: [PATCH 0154/3720] For the time being, set prefix= On MinGW, we want to install git in /bin. Signed-off-by: Johannes Schindelin --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 85df9a5c67..24bf460a1d 100644 --- a/Makefile +++ b/Makefile @@ -493,8 +493,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) EXTLIBS += -lws2_32 X = .exe NOEXECTEMPL = .noexec - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig + prefix = SCRIPT_SH += cpio.sh endif ifneq (,$(findstring arm,$(uname_M))) From 0e2bdc35afa484b521b7af2e74ad661b732d92eb Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Fri, 3 Aug 2007 19:27:53 -0400 Subject: [PATCH 0155/3720] Add and use expat and curl to enable http://. The expat build was added and the pieces of curl that seemed missing. The default NO_CURL was removed so that curl is used by default. Signed-off-by: Mike Pape --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24bf460a1d..4103eca01b 100644 --- a/Makefile +++ b/Makefile @@ -474,7 +474,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MMAP=YesPlease NO_PREAD=YesPlease NO_OPENSSL=YesPlease - NO_CURL=YesPlease NO_SYMLINK_HEAD=YesPlease NO_IPV6=YesPlease NO_ETC_PASSWD=YesPlease @@ -488,6 +487,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease + NO_R_TO_GCC_LINKER = YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 From ef5af72062ef0e0c0b5d8a7a3dda89b0609050bc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 4 Aug 2007 15:28:24 +0100 Subject: [PATCH 0156/3720] Minimal changes to allow for GIT_TRACE=/trace.txt (is_absolute_path()) This imitates what is currently in git.git's master: a function to determine if a path is absolute. msysgit.git is not really the proper place to fix this, but Hannes is still on holiday. Signed-off-by: Johannes Schindelin --- cache.h | 4 ++++ trace.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cache.h b/cache.h index e0a5f6decd..91e9f7109f 100644 --- a/cache.h +++ b/cache.h @@ -359,6 +359,10 @@ 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] == '/' || (isalpha(path[0]) && path[1] == ':'); +} /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/trace.c b/trace.c index 7961a27a2e..344066e88b 100644 --- a/trace.c +++ b/trace.c @@ -64,7 +64,7 @@ static int get_trace_fd(int *need_close) return STDERR_FILENO; if (strlen(trace) == 1 && isdigit(*trace)) return atoi(trace); - if (*trace == '/') { + if (is_absolute_path(trace)) { int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd == -1) { fprintf(stderr, From 4a66a6c4c236827c3ea89c75f908bf8019b3758c Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Sat, 4 Aug 2007 04:38:13 -0700 Subject: [PATCH 0157/3720] Correctly test for absolute path This fix (while correct) actually avoids another nasty bug that must be fixed later: environment.c caches results of many getenv calls. Under MinGW setenv(X) invalidates all previous values returned by getenv(X) so cached values become dangling pointers. Signed-off-by: Dmitry Kakurin Signed-off-by: Johannes Schindelin --- setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.c b/setup.c index e921013926..4d14541bcc 100644 --- a/setup.c +++ b/setup.c @@ -332,7 +332,7 @@ const char *setup_git_directory_gently(int *nongit_ok) * In case there is a work tree we may change the directory, * therefore make GIT_DIR an absolute path. */ - if (gitdirenv[0] != '/') { + if (!is_absolute_path(gitdirenv)) { setenv(GIT_DIR_ENVIRONMENT, gitdir, 1); gitdirenv = getenv(GIT_DIR_ENVIRONMENT); if (!gitdirenv) From 13e33743145fced9306fc7594bc84514fbd5883c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 5 Aug 2007 05:49:59 +0100 Subject: [PATCH 0158/3720] Trace ssh connections when GIT_TRACE is set This is really a patch for mingw.git. Signed-off-by: Johannes Schindelin --- rsh.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rsh.c b/rsh.c index 5754a230e2..9bb03d12c6 100644 --- a/rsh.c +++ b/rsh.c @@ -71,6 +71,8 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, ssh_basename = ssh; else ssh_basename++; + trace_printf("Calling '%s' '%s' '%s' '%s'\n", + ssh, ssh_basename, host, command); close(sv[1]); dup2(sv[0], 0); dup2(sv[0], 1); From 60096146d67d408837b80c6b720bee722f35cf72 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 16:49:51 +0100 Subject: [PATCH 0159/3720] Work around MinGW mangling of "host:/path" The common way to specify an ssh remote is to say "host:/path", but MinGW decides for us that this is probably a path list, and path lists are separated by a semicolon on Windows. So before passing this to git-peek-remote.exe, it transforms that to "host;C:/msysGit/path". Avoid that by expanding it to "ssh://host/path", but take extra care not to convert absolute paths to that syntax! Signed-off-by: Johannes Schindelin --- git-parse-remote.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100755 => 100644 git-parse-remote.sh diff --git a/git-parse-remote.sh b/git-parse-remote.sh old mode 100755 new mode 100644 index 695a4094bb..7c0d242eec --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -51,7 +51,8 @@ get_remote_url () { ;; *) die "internal error: get-remote-url $1" ;; - esac + esac | sed "s|^\(.[^:][^:]*\):\(/[^/]\)|ssh://\1\2|" + # work around MinGW path mangling } get_default_remote () { From 3d9012418c93b5e5f0ada041e1fc071cac48cbfa Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Mon, 6 Aug 2007 16:11:19 -0400 Subject: [PATCH 0160/3720] Added is_dev_null check because Windows /dev/null is nul. This function should be called to test for /dev/null when nul on Windows can also be accepted. The is_dev_null function in builtin-apply.c was renamed. Signed-off-by: Mike Pape --- builtin-apply.c | 8 ++++---- cache.h | 9 +++++++++ diff-lib.c | 6 +++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 0a0b4a9e3f..f8cde7f3f5 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -222,7 +222,7 @@ static unsigned long linelen(const char *buffer, unsigned long size) return len; } -static int is_dev_null(const char *str) +static int is_dev_null_line(const char *str) { return !memcmp("/dev/null", str, 9) && isspace(str[9]); } @@ -333,7 +333,7 @@ static int guess_p_value(const char *nameline) char *name, *cp; int val = -1; - if (is_dev_null(nameline)) + if (is_dev_null_line(nameline)) return -1; name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB); if (!name) @@ -381,12 +381,12 @@ static void parse_traditional_patch(const char *first, const char *second, struc p_value_known = 1; } } - if (is_dev_null(first)) { + if (is_dev_null_line(first)) { patch->is_new = 1; patch->is_delete = 0; name = find_name(second, NULL, p_value, TERM_SPACE | TERM_TAB); patch->new_name = name; - } else if (is_dev_null(second)) { + } else if (is_dev_null_line(second)) { patch->is_new = 0; patch->is_delete = 1; name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB); diff --git a/cache.h b/cache.h index 91e9f7109f..f13e1b74a1 100644 --- a/cache.h +++ b/cache.h @@ -364,6 +364,15 @@ static inline int is_absolute_path(const char *path) return path[0] == '/' || (isalpha(path[0]) && path[1] == ':'); } +static inline int is_dev_null(const char *str) +{ +#ifdef __MINGW32__ + if (!strcmp(str, "nul")) + return 1; +#endif + return !strcmp(str, "/dev/null"); +} + /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size); diff --git a/diff-lib.c b/diff-lib.c index 92c0e39ad6..9a424621ed 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -34,7 +34,7 @@ static int get_mode(const char *path, int *mode) { struct stat st; - if (!path || !strcmp(path, "/dev/null")) + if (!path || is_dev_null(path)) *mode = 0; else if (!strcmp(path, "-")) *mode = ntohl(create_ce_mode(0666)); @@ -229,6 +229,10 @@ static int is_outside_repo(const char *path, int nongit, const char *prefix) int i; if (nongit || !strcmp(path, "-") || path[0] == '/') return 1; +#ifdef __MINGW32__ + if (!strcmp(path, "nul")) + return 1; +#endif if (prefixcmp(path, "../")) return 0; if (!prefix) From f1e1dc5119bd9862bb4d2a975c8ca6362ea43af5 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Tue, 7 Aug 2007 07:58:08 +0200 Subject: [PATCH 0161/3720] Use builtin config function when installing. As the symlink for git-config is not set up yet at this point, we use the builtin instead. Signed-off-by: Marius Storm-Olsen --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4103eca01b..2f83c432bc 100644 --- a/Makefile +++ b/Makefile @@ -1005,7 +1005,7 @@ install: all $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)' GIT_CONFIG='$(DESTDIR_SQ)$(sysconfdir_SQ)/gitconfig' \ - $(DESTDIR_SQ)$(bindir_SQ)/git-config$X core.symlinks false + $(DESTDIR_SQ)$(bindir_SQ)/git$X config core.symlinks false $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' install ifndef NO_TCLTK From 8ca1f6af8c343172ca885076b8e581137ac05faf Mon Sep 17 00:00:00 2001 From: Julian Phillips Date: Tue, 17 Jul 2007 22:14:06 +0100 Subject: [PATCH 0162/3720] git-gui: Handle git versions of the form n.n.n.GIT The git-gui version check doesn't handle versions of the form n.n.n.GIT which you can get by installing from an tarball produced by git-archive. Without this change you get an error of the form: 'Error in startup script: expected version number but got "1.5.3.GIT"' Signed-off-by: Julian Phillips Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 2077261e64..f8b1f10187 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -546,6 +546,7 @@ if {![regsub {^git version } $_git_version {} _git_version]} { } regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version regsub {\.rc[0-9]+$} $_git_version {} _git_version +regsub {\.GIT$} $_git_version {} _git_version proc git-version {args} { global _git_version From 637fc51696dc067c006b1651689b2f0aac26ec04 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 7 Aug 2007 20:50:42 +0200 Subject: [PATCH 0163/3720] Implement is_absolute_path() on Windows. To keep the brief, we don't check that there must be a letter before the colon and a slash or backslash after the colon - we just assume that we don't have to work with drive-relative paths. --- cache.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cache.h b/cache.h index d9598bb685..a701139fd8 100644 --- a/cache.h +++ b/cache.h @@ -364,7 +364,11 @@ int safe_create_leading_directories(char *path); char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) { +#ifndef __MINGW32__ return path[0] == '/'; +#else + return path[0] == '/' || (path[0] && path[1] == ':'); +#endif } const char *make_absolute_path(const char *path); From ab793ce23595a1d7b4891646dc5d9a04af720211 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 7 Aug 2007 22:24:03 +0200 Subject: [PATCH 0164/3720] Work around misbehaved rename() on Windows. Windows's rename() is based on the MoveFile() API, which fails if the destination exists. Here we work around the problem by using MoveFileEx(). Furthermore, the posixly correct error is returned if the destination is a directory. The implementation is still slightly incomplete, however, because of the missing error code translation: We assume that the failure is due to permissions. --- builtin-reflog.c | 6 ------ compat/mingw.c | 25 +++++++++++++++++++++++++ git-compat-util.h | 3 +++ lockfile.c | 1 - refs.c | 10 ---------- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/builtin-reflog.c b/builtin-reflog.c index 27e251ff6d..ce093cad78 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -269,12 +269,6 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, if (fclose(cb.newlog)) status |= error("%s: %s", strerror(errno), newlog_path); -#ifdef __MINGW32__ - /* rename fails if the destination exists */ - if (unlink(log_file)) - status |= error("cannot remove %s", log_file); - else -#endif if (rename(newlog_path, log_file)) { status |= error("cannot rename %s to %s", newlog_path, log_file); diff --git a/compat/mingw.c b/compat/mingw.c index ac8b8e0414..7711a3fb39 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -322,3 +322,28 @@ int mingw_socket(int domain, int type, int protocol) } return s; } + +#undef rename +int mingw_rename(const char *pold, const char *pnew) +{ + /* + * Try native rename() first to get errno right. + * It is based on MoveFile(), which cannot overwrite existing files. + */ + if (!rename(pold, pnew)) + return 0; + if (errno != EEXIST) + return -1; + if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) + return 0; + /* TODO: translate more errors */ + if (GetLastError() == ERROR_ACCESS_DENIED) { + struct stat st; + if (!stat(pnew, &st) && S_ISDIR(st.st_mode)) { + errno = EISDIR; + return -1; + } + } + errno = EACCES; + return -1; +} diff --git a/git-compat-util.h b/git-compat-util.h index ddafec997f..98ad78d571 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -466,6 +466,9 @@ char *mingw_getcwd(char *pointer, int len); int mingw_socket(int domain, int type, int protocol); #define socket mingw_socket +int mingw_rename(const char*, const char*); +#define rename mingw_rename + #define setlinebuf(x) #define fsync(x) 0 diff --git a/lockfile.c b/lockfile.c index 84a6aa33bd..258fb3f5ef 100644 --- a/lockfile.c +++ b/lockfile.c @@ -167,7 +167,6 @@ int commit_lock_file(struct lock_file *lk) strcpy(result_file, lk->filename); i = strlen(result_file) - 5; /* .lock */ result_file[i] = 0; - unlink(result_file); i = rename(lk->filename, result_file); lk->filename[0] = 0; return i; diff --git a/refs.c b/refs.c index 3c477309bb..9c07f83b72 100644 --- a/refs.c +++ b/refs.c @@ -963,15 +963,6 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg) retry: if (log && rename(git_path("tmp-renamed-log"), git_path("logs/%s", newref))) { -#ifdef __MINGW32__ - if (errno == EEXIST) { - struct stat st; - if (stat(git_path("logs/%s", newref), &st) == 0 && S_ISDIR(st.st_mode)) - errno = EISDIR; - else - errno = EEXIST; - } -#endif if (errno==EISDIR || errno==ENOTDIR) { /* * rename(a, b) when b is an existing @@ -1237,7 +1228,6 @@ int create_symref(const char *ref_target, const char *refs_heads_master, error("Unable to write to %s", lockpath); goto error_unlink_return; } - unlink(git_HEAD); if (rename(lockpath, git_HEAD) < 0) { error("Unable to create %s", git_HEAD); goto error_unlink_return; From 1c32cf28d70781ebb843d436558e0b328b438ec6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 7 Aug 2007 22:25:13 +0200 Subject: [PATCH 0165/3720] Skip again some tests involving symbolic links. --- t/t0000-basic.sh | 1 + t/t1300-repo-config.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 2c3b6b797c..a213268cd6 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -305,6 +305,7 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' +test "$no_symlinks" || test_expect_success 'absolute path works as expected' ' mkdir first && ln -s ../.git first/.git && diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 1d2bf2c060..12285d674b 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -601,6 +601,7 @@ echo >>result test_expect_success '--null --get-regexp' 'cmp result expect' +test "$no_symlinks" || test_expect_success 'symlinked configuration' ' ln -s notyet myconfig && From 52b4f704fd0d3f1ced8419cbcb460dd8374d8220 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 7 Aug 2007 22:26:45 +0200 Subject: [PATCH 0166/3720] builtin run_command: do not exit with -1. The shell does not correctly detect an exit code of -1 as a failure. We simply truncate the status code to the lower 8 bits. --- git.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git.c b/git.c index fd604b51fc..adbc188d86 100644 --- a/git.c +++ b/git.c @@ -288,7 +288,7 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv) status = p->fn(argc, argv, prefix); if (status) - return status; + return status & 0xff; /* Somebody closed stdout? */ if (fstat(fileno(stdout), &st)) From c603988c10c1d897e6f15e18b7727ec1bb1711b9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 8 Aug 2007 21:35:02 +0200 Subject: [PATCH 0167/3720] t/test-lib.sh: Automatically detect whether symbolic links are supported. This reverts the part of commit cb0ad0c0af084b52a72791feeca7c70bd8ed855a that hands down the explicit NO_SYMLINKS setting from the top-level Makefile. --- Makefile | 2 -- t/Makefile | 4 ---- t/test-lib.sh | 6 ++++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index f94bf01450..8127a5569d 100644 --- a/Makefile +++ b/Makefile @@ -492,7 +492,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease - NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat @@ -987,7 +986,6 @@ all: $(TEST_PROGRAMS) # However, the environment gets quite big, and some programs have problems # with that. -export NO_SYMLINKS export NO_SVN_TESTS test: all diff --git a/t/Makefile b/t/Makefile index f8e396c108..72d7884232 100644 --- a/t/Makefile +++ b/t/Makefile @@ -14,10 +14,6 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) TSVN = $(wildcard t91[0-9][0-9]-*.sh) -ifdef NO_SYMLINKS - GIT_TEST_OPTS += --no-symlinks -endif - all: $(T) clean $(T): diff --git a/t/test-lib.sh b/t/test-lib.sh index 6081d172ab..a3f3d7c922 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -87,8 +87,6 @@ do --no-python) # noop now... shift ;; - --no-symlinks) - no_symlinks=t; shift ;; *) break ;; esac @@ -285,6 +283,10 @@ rm -fr "$test" test_create_repo $test cd "$test" +# test for symbolic link capability +ln -s x y 2> /dev/null && test -l y 2> /dev/null || no_symlinks=1 +rm -f y + this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$') for skp in $GIT_SKIP_TESTS do From 7e6ad42588fb341f1328acb072f0720a4c411705 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:11:54 +0200 Subject: [PATCH 0168/3720] Skip some git diff tests if the file system does not support funny names. Signed-off-by: Johannes Sixt --- t/t3902-quoted.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh index 63f950b179..e8ad85afe4 100755 --- a/t/t3902-quoted.sh +++ b/t/t3902-quoted.sh @@ -14,6 +14,13 @@ LF=' ' DQ='"' +echo foo > "Name and an${HT}HT" +test -f "Name and an${HT}HT" || { + # since FAT/NTFS does not allow tabs in filenames, skip this test + say 'Your filesystem does not allow tabs in filenames, test skipped.' + test_done +} + for_each_name () { for name in \ Name "Name and a${LF}LF" "Name and an${HT}HT" "Name${DQ}" \ From 6bb4b679d6fcee5104c46c3a5750cbe1d1dc06ce Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 9 Aug 2007 01:54:12 +0100 Subject: [PATCH 0169/3720] Fix new tests which ignored --no-symlinks Signed-off-by: Johannes Schindelin --- t/t0000-basic.sh | 2 ++ t/t1300-repo-config.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 2c3b6b797c..b42b1e6948 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -305,6 +305,7 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' +test "$no_symlinks" || { test_expect_success 'absolute path works as expected' ' mkdir first && ln -s ../.git first/.git && @@ -320,5 +321,6 @@ test_expect_success 'absolute path works as expected' ' sym="$(cd first; pwd -P)"/file && test "$sym" = "$(test-absolute-path $dir2/syml)" ' +} test_done diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 1d2bf2c060..a59f1f3aed 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -601,6 +601,7 @@ echo >>result test_expect_success '--null --get-regexp' 'cmp result expect' +test "$no_symlinks" || { test_expect_success 'symlinked configuration' ' ln -s notyet myconfig && @@ -615,5 +616,6 @@ test_expect_success 'symlinked configuration' ' test "z$(GIT_CONFIG=notyet git config test.xyzzy)" = zrezrov ' +} test_done From 327005a9ef9c3b784e4742cece0710de6a549313 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Wed, 8 Aug 2007 22:19:49 -0400 Subject: [PATCH 0170/3720] Returning -1 does not fail like it should in MSys. We need to return 1 rather than -1 on failure since -1 does not seem to signal an error in MSys. Signed-off-by: Mike Pape --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.c b/config.c index bbc5d34e5a..977115a6e9 100644 --- a/config.c +++ b/config.c @@ -436,7 +436,7 @@ int git_config_from_file(config_fn_t fn, const char *filename) int ret; FILE *f = fopen(filename, "r"); - ret = -1; + ret = 1; if (f) { config_file = f; config_file_name = filename; From cfbeb65f6e9a2a990a4feaaf0475b226acda44c0 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 13:29:48 -0400 Subject: [PATCH 0171/3720] Added a sleep to the test for MSys so commits happen. When committing, git thought there were no changes. Signed-off-by: Mike Pape --- t/t6200-fmt-merge-msg.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 526d7d1c44..878f51a8d9 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -9,6 +9,7 @@ test_description='fmt-merge-msg test' datestamp=1151939923 setdate () { + sleep 1 GIT_COMMITTER_DATE="$datestamp +0200" GIT_AUTHOR_DATE="$datestamp +0200" datestamp=`expr "$datestamp" + 1` From e11db787dc8e680b379303393949da6ee2c45f0b Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 14:30:18 -0400 Subject: [PATCH 0172/3720] We need to check for msys as well as Windows in add--interactive. Signed-off-by: Mike Pape --- git-add--interactive.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 7921cde8cb..717960037c 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -3,7 +3,7 @@ use strict; sub run_cmd_pipe { - if ($^O eq 'MSWin32') { + if ($^O eq 'MSWin32' || $^O eq 'msys') { my @invalid = grep {m/[":*]/} @_; die "$^O does not support: @invalid\n" if @invalid; my @args = map { m/ /o ? "\"$_\"": $_ } @_; From a917ddbacf11b1f2280134bd8bc5c248fbf77a5d Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 14:35:43 -0400 Subject: [PATCH 0173/3720] sed does not accept -i on msys. We use a temporary .new file instead. Signed-off-by: Mike Pape --- t/t7501-commit.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 6bd3c9e3e0..cfa67227e5 100644 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -69,7 +69,8 @@ test_expect_success \ cat >editor <<\EOF #!/bin/sh -sed -i -e "s/a file/an amend commit/g" $1 +sed -e "s/a file/an amend commit/g" $1 > $1.new +mv $1.new $1 EOF chmod 755 editor @@ -88,7 +89,8 @@ test_expect_success \ cat >editor <<\EOF #!/bin/sh -sed -i -e "s/amend/older/g" $1 +sed -e "s/amend/older/g" $1 > $1.new +mv $1.new $1 EOF chmod 755 editor From 96f438b98a7b8b3fec062ed6064d74074e5e1ff0 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 16:18:50 -0400 Subject: [PATCH 0174/3720] In msys, chmod does not work. Using the shebang makes it "executable". Thanks to Dscho for figuring out the work around. Signed-off-by: Mike Pape --- t/t7005-editor.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh index 28643b0da4..b21ced1bc2 100755 --- a/t/t7005-editor.sh +++ b/t/t7005-editor.sh @@ -7,6 +7,7 @@ test_description='GIT_EDITOR, core.editor, and stuff' for i in GIT_EDITOR core_editor EDITOR VISUAL vi do cat >e-$i.sh <<-EOF + #!/bin/sh echo "Edited by $i" >"\$1" EOF chmod +x e-$i.sh From 733bd67d92a3dfa0a10a4c17ebbe82195891bd3e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 9 Aug 2007 22:32:09 +0200 Subject: [PATCH 0175/3720] Fix mode of shell scripts. These are the result of mismerges by old Windows versions of git. --- git-clone.sh | 0 git-rebase.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 git-clone.sh mode change 100644 => 100755 git-rebase.sh diff --git a/git-clone.sh b/git-clone.sh old mode 100644 new mode 100755 diff --git a/git-rebase.sh b/git-rebase.sh old mode 100644 new mode 100755 From 37ebf62c74202db267d2eb33283555d614edc70b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 9 Aug 2007 22:33:20 +0200 Subject: [PATCH 0176/3720] Revert style breakage. The breakage is a result of editing and incomplete reversal. --- builtin-prune-packed.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 6473d327e6..977730064b 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -25,10 +25,8 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) memcpy(pathname + len, de->d_name, 38); if (opts & DRY_RUN) printf("rm -f %s\n", pathname); - else { - if (unlink(pathname) < 0) - error("unable to unlink %s", pathname); - } + else if (unlink(pathname) < 0) + error("unable to unlink %s", pathname); } pathname[len] = 0; rmdir(pathname); From decd70079244e8daa16eb49c95f82c407629b540 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 9 Aug 2007 23:07:30 +0200 Subject: [PATCH 0177/3720] Use is_absolute_path() in more places. --- builtin-init-db.c | 2 +- config.c | 2 +- exec_cmd.c | 12 ++---------- git.c | 14 ++++---------- setup.c | 5 +---- 5 files changed, 9 insertions(+), 26 deletions(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index 2a20737249..c51c586141 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -140,7 +140,7 @@ static void copy_templates(const char *git_dir, int len, const char *template_di * interpreted relative to the exec_dir */ template_dir = DEFAULT_GIT_TEMPLATE_DIR; - if (template_dir[0] != '/' && template_dir[1] != ':') { + if (!is_absolute_path(template_dir)) { const char *exec_path = git_exec_path(); template_dir = prefix_path(exec_path, strlen(exec_path), template_dir); diff --git a/config.c b/config.c index fb4576f87f..78bd267070 100644 --- a/config.c +++ b/config.c @@ -454,7 +454,7 @@ const char *git_etc_gitconfig(void) if (!system_wide) { system_wide = ETC_GITCONFIG; /* interpret path relative to exec-dir */ - if (system_wide[0] != '/' && system_wide[1] != ':') { + if (!is_absolute_path(system_wide)) { const char *exec_path = git_exec_path(); system_wide = prefix_path(exec_path, strlen(exec_path), system_wide); diff --git a/exec_cmd.c b/exec_cmd.c index a9886b87fd..bad4843113 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -80,11 +80,7 @@ int execv_git_cmd(const char **argv) if (!exec_dir || !*exec_dir) continue; -#ifdef __MINGW32__ - if (*exec_dir != '/' && exec_dir[1] != ':') { -#else - if (*exec_dir != '/') { -#endif + if (!is_absolute_path(exec_dir)) { if (!getcwd(git_command, sizeof(git_command))) { fprintf(stderr, "git: cannot determine " "current directory: %s\n", @@ -190,11 +186,7 @@ int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) if (!exec_dir || !*exec_dir) continue; -#ifdef __MINGW32__ - if (*exec_dir != '/' && exec_dir[1] != ':') { -#else - if (*exec_dir != '/') { -#endif + if (!is_absolute_path(exec_dir)) { if (!getcwd(p[i], sizeof(p[i]))) { fprintf(stderr, "git: cannot determine " "current directory: %s\n", diff --git a/git.c b/git.c index adbc188d86..9908a60007 100644 --- a/git.c +++ b/git.c @@ -422,22 +422,16 @@ int main(int argc, const char **argv) * if it's an absolute path and we don't have * anything better. */ - if (slash) { - *slash++ = 0; - if (*cmd == '/') - exec_path = cmd; - cmd = slash; - } - #ifdef __MINGW32__ - slash = strrchr(cmd, '\\'); + if (!slash) + slash = strrchr(cmd, '\\'); +#endif if (slash) { *slash++ = 0; - if (cmd[1] == ':') + if (is_absolute_path(cmd)) exec_path = cmd; cmd = slash; } -#endif /* * "git-xxxx" is the same as "git xxxx", but we obviously: diff --git a/setup.c b/setup.c index fa5f724d21..15100bc1b7 100644 --- a/setup.c +++ b/setup.c @@ -88,10 +88,7 @@ const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) return arg; #else /* don't add prefix to absolute paths */ - const int is_absolute = - is_dir_sep(arg[0]) || - (arg[0] && arg[1] == ':' && is_dir_sep(arg[2])); - if (is_absolute) + if (is_absolute_path(arg)) pfx_len = 0; else #endif From dfcdb3d9fc34a6a6f50e00934af014e0fc62f0c6 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 20:05:38 -0400 Subject: [PATCH 0178/3720] Fixed INSTALL set in Makefile from the merge with git.git. INSTALL was set to /bin/install but then set to install right after that from the merge. MSys needs to have the explicit path so it doesn't use Windows install. Signed-off-by: Mike Pape --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 36d7bebbad..f3f08dbcc4 100644 --- a/Makefile +++ b/Makefile @@ -179,7 +179,6 @@ RM = rm -f TAR = tar FIND = find INSTALL = /bin/install -INSTALL = install RPMBUILD = rpmbuild TCL_PATH = tclsh TCLTK_PATH = wish From 855f254b2b5b083a63fc8d7709a42e2cbdc5a136 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Thu, 9 Aug 2007 13:41:02 -0700 Subject: [PATCH 0179/3720] git clone was failing with 'invalid object name HEAD' if ran from cmd.exe directly environment.c caches results of many getenv calls. Under MinGW setenv(X) invalidates all previous values returned by getenv(X) so cached values become dangling pointers. Replaced all setenv(GIT_DIR, ...) with set_git_dir Signed-off-by: Dmitry Kakurin --- builtin-init-db.c | 4 +--- git.c | 6 +++--- path.c | 2 +- setup.c | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index 2a20737249..31427c571d 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -318,9 +318,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) /* * Set up the default .git directory contents */ - git_dir = getenv(GIT_DIR_ENVIRONMENT); - if (!git_dir) - git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; + git_dir = get_git_dir(); safe_create_dir(git_dir, 0); /* Check to see if the repository version is right. diff --git a/git.c b/git.c index 1f7f595653..5fc277c895 100644 --- a/git.c +++ b/git.c @@ -67,14 +67,14 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) fprintf(stderr, "No directory given for --git-dir.\n" ); usage(git_usage_string); } - setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1); + set_git_dir( (*argv)[1] ); if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; handled++; } else if (!prefixcmp(cmd, "--git-dir=")) { - setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); + set_git_dir(cmd + 10); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { @@ -93,7 +93,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--bare")) { static char git_dir[PATH_MAX+1]; - setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1); + set_git_dir(getcwd(git_dir, sizeof(git_dir))); if (envchanged) *envchanged = 1; } else { diff --git a/path.c b/path.c index a1139d483b..7a5ac5b067 100644 --- a/path.c +++ b/path.c @@ -265,7 +265,7 @@ char *enter_repo(char *path, int strict) if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 && validate_headref("HEAD") == 0) { - setenv(GIT_DIR_ENVIRONMENT, ".", 1); + set_git_dir("."); check_repository_format(); return path; } diff --git a/setup.c b/setup.c index 5a8e7b6b52..0de8dcd61b 100644 --- a/setup.c +++ b/setup.c @@ -332,7 +332,7 @@ const char *setup_git_directory_gently(int *nongit_ok) inside_git_dir = 1; if (!work_tree_env) inside_work_tree = 0; - setenv(GIT_DIR_ENVIRONMENT, ".", 1); + set_git_dir("."); return NULL; } chdir(".."); From 5e5619bd48dab2c8a32c604001ffaae6f807b1af Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Fri, 10 Aug 2007 01:09:34 -0700 Subject: [PATCH 0180/3720] Applied settings from config.mak to Makefile so we don't need config.mak anymore Signed-off-by: Dmitry Kakurin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f3f08dbcc4..dd31119098 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ ALL_CFLAGS = $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) STRIP ?= strip -prefix = $(HOME) +prefix = bindir = $(prefix)/bin gitexecdir = $(bindir) sharedir = $(prefix)/share From a8c36f3212670a10d71203e91f97089f8954f624 Mon Sep 17 00:00:00 2001 From: Torgil Svensson Date: Fri, 10 Aug 2007 10:02:51 +0200 Subject: [PATCH 0181/3720] Make sane shell- and perl-scripts magic paths Make the magic paths absolute to msys instead of absolute to Windows. Signed-off-by: Torgil Svensson Acked-by: Johannes Schindelin Acked-by: Marius Storm-Olsen --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index dd31119098..0eada9d4c8 100644 --- a/Makefile +++ b/Makefile @@ -475,8 +475,8 @@ ifeq ($(uname_S),IRIX64) BASIC_LDFLAGS += -L/usr/lib32 endif ifneq (,$(findstring MINGW,$(uname_S))) - SHELL_PATH = $(shell cd /bin && pwd -W)/sh - PERL_PATH = $(shell cd /bin && pwd -W)/perl + SHELL_PATH = /bin/sh + PERL_PATH = /bin/perl NO_MMAP=YesPlease NO_PREAD=YesPlease NO_OPENSSL=YesPlease From 8e78bd571071805ca9f34a6bc93846f6e5b15f4e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 10 Aug 2007 11:33:40 +0100 Subject: [PATCH 0182/3720] verify_path(): do not allow absolute paths Signed-off-by: Johannes Schindelin --- read-cache.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/read-cache.c b/read-cache.c index e060392d1d..abc41561df 100644 --- a/read-cache.c +++ b/read-cache.c @@ -507,6 +507,11 @@ int verify_path(const char *path) { char c; +#ifdef __MINGW32__ + if (is_absolute_path(path)) + return error("Cannot handle absolute path: %s", path); +#endif + goto inside; for (;;) { if (!c) From ec33dd4c530319fc95f5481d057b2ad940e91694 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 11 Aug 2007 22:14:34 +0200 Subject: [PATCH 0183/3720] t7501-commit.sh: Not all seds understand option -i Use mv instead. Signed-off-by: Johannes Sixt --- t/t7501-commit.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 6bd3c9e3e0..d1284140d7 100644 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -69,7 +69,8 @@ test_expect_success \ cat >editor <<\EOF #!/bin/sh -sed -i -e "s/a file/an amend commit/g" $1 +sed -e "s/a file/an amend commit/g" < $1 > $1- +mv $1- $1 EOF chmod 755 editor @@ -88,7 +89,8 @@ test_expect_success \ cat >editor <<\EOF #!/bin/sh -sed -i -e "s/amend/older/g" $1 +sed -e "s/amend/older/g" < $1 > $1- +mv $1- $1 EOF chmod 755 editor From 89697a4c152c798205c9af4782e4053274e54b3f Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Sun, 12 Aug 2007 05:30:07 -0700 Subject: [PATCH 0184/3720] Issue 20: Fix all build warnings Fixed all warnings. Code compiles cleanly now. Full test pass: OK Signed-off-by: Dmitry Kakurin --- builtin-ls-files.c | 2 +- builtin-prune-packed.c | 2 ++ builtin-prune.c | 2 ++ builtin-unpack-objects.c | 2 +- compat/mingw.c | 4 ++-- compat/pread.c | 2 ++ compat/regex.c | 26 ++++++++++++++++---------- config.c | 2 ++ connect.c | 2 +- diff.c | 2 +- exec_cmd.c | 5 ++--- fetch-pack.c | 2 +- index-pack.c | 2 +- merge-index.c | 2 +- pager.c | 2 +- read-cache.c | 2 +- receive-pack.c | 2 +- run-command.c | 4 ++-- sha1_file.c | 16 +++++++++------- show-index.c | 2 +- spawn-pipe.c | 6 ++---- unpack-trees.c | 2 +- 22 files changed, 53 insertions(+), 40 deletions(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index d36181a755..e83b145b5c 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -211,7 +211,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) putchar(line_terminator); } else { - printf("%s%06o %s %d\t", + printf("%s%06lo %s %u\t", tag, ntohl(ce->ce_mode), abbrev ? find_unique_abbrev(ce->sha1,abbrev) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 6473d327e6..fa9ad7bfdf 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -7,6 +7,8 @@ static const char prune_packed_usage[] = #define DRY_RUN 01 #define VERBOSE 02 +void sync(void); + static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) { struct dirent *de; diff --git a/builtin-prune.c b/builtin-prune.c index 44df59e4a7..02e4c09b0e 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -8,6 +8,8 @@ static const char prune_usage[] = "git-prune [-n]"; static int show_only; +void sync(void); + static int prune_object(char *path, const char *filename, const unsigned char *sha1) { if (show_only) { diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index a6ff62fd8c..1500be5761 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -318,7 +318,7 @@ static void unpack_all(void) if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE) die("bad pack file"); if (!pack_version_ok(hdr->hdr_version)) - die("unknown pack file version %d", ntohl(hdr->hdr_version)); + die("unknown pack file version %lu", ntohl(hdr->hdr_version)); use(sizeof(struct pack_header)); if (!quiet) diff --git a/compat/mingw.c b/compat/mingw.c index ac8b8e0414..ca3ae4cb06 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -131,7 +131,7 @@ int pipe(int filedes[2]) CloseHandle(h[0]); return -1; } - fd = _open_osfhandle(h[0], O_NOINHERIT); + fd = _open_osfhandle( (int) h[0], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); @@ -141,7 +141,7 @@ int pipe(int filedes[2]) } close(filedes[0]); filedes[0] = fd; - fd = _open_osfhandle(h[1], O_NOINHERIT); + fd = _open_osfhandle( (int) h[1], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); diff --git a/compat/pread.c b/compat/pread.c index 978cac4ec9..ce29997724 100644 --- a/compat/pread.c +++ b/compat/pread.c @@ -1,5 +1,7 @@ #include "../git-compat-util.h" +int read_in_full(int fd, void *buf, size_t count); + ssize_t git_pread(int fd, void *buf, size_t count, off_t offset) { off_t current_offset; diff --git a/compat/regex.c b/compat/regex.c index 2d57c70b9c..1d39e08d47 100644 --- a/compat/regex.c +++ b/compat/regex.c @@ -1597,10 +1597,12 @@ regex_compile (pattern, size, syntax, bufp) if (syntax & RE_NO_BK_PARENS) goto normal_backslash; if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_backslash; else return REG_ERPAREN; + } handle_close: if (fixup_alt_jump) @@ -1617,10 +1619,12 @@ regex_compile (pattern, size, syntax, bufp) /* See similar code for backslashed left paren above. */ if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_char; else return REG_ERPAREN; + } /* Since we just checked for an empty stack above, this ``can't happen''. */ @@ -3191,14 +3195,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matching and the regnum-th regend points to right after where we stopped matching the regnum-th subexpression. (The zeroth register keeps track of what the whole pattern matches.) */ - const char **regstart, **regend; + const char **regstart = NULL, **regend = NULL; /* If a group that's operated upon by a repetition operator fails to match anything, then the register for its start will need to be restored because it will have been set to wherever in the string we are when we last see its open-group operator. Similarly for a register's end. */ - const char **old_regstart, **old_regend; + const char **old_regstart = NULL, **old_regend = NULL; /* The is_active field of reg_info helps us keep track of which (possibly nested) subexpressions we are currently in. The matched_something @@ -3206,14 +3210,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matched any of the pattern so far this time through the reg_num-th subexpression. These two fields get reset each time through any loop their register is in. */ - register_info_type *reg_info; + register_info_type *reg_info = NULL; /* The following record the register info as found in the above variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = false; - const char **best_regstart, **best_regend; + const char **best_regstart = NULL, **best_regend = NULL; /* Logically, this is `best_regend[0]'. But we don't want to have to allocate space for that if we're not allocating space for anything @@ -3226,8 +3230,8 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) const char *match_end = NULL; /* Used when we pop values we don't care about. */ - const char **reg_dummy; - register_info_type *reg_info_dummy; + const char **reg_dummy = NULL; + register_info_type *reg_info_dummy = NULL; #ifdef DEBUG /* Counts the total number of registers pushed. */ @@ -4561,10 +4565,12 @@ common_op_match_null_string_p (p, end, reg_info) bytes; nonzero otherwise. */ static int -bcmp_translate (s1, s2, len, translate) - unsigned char *s1, *s2; - register int len; - char *translate; +bcmp_translate( + unsigned char *s1, + unsigned char *s2, + int len, + char *translate +) { register unsigned char *p1 = s1, *p2 = s2; while (len) diff --git a/config.c b/config.c index 977115a6e9..98ae20d551 100644 --- a/config.c +++ b/config.c @@ -15,6 +15,8 @@ static const char *config_file_name; static int config_linenr; static int zlib_compression_seen; +extern int getpagesize(); + static int get_next_char(void) { int c; diff --git a/connect.c b/connect.c index f50db639a4..dcae813b58 100644 --- a/connect.c +++ b/connect.c @@ -585,7 +585,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) const char *argv[] = { NULL, host, command, NULL }; const char *ssh = getenv("GIT_SSH"); if (!ssh) ssh = "ssh"; - pid = spawnvpe_pipe(ssh, argv, environ, pipefd[1], pipefd[0]); + pid = spawnvpe_pipe(ssh, argv, (const char**) environ, pipefd[1], pipefd[0]); } else { const char *argv[] = { NULL, "-c", command, NULL }; diff --git a/diff.c b/diff.c index e64625129d..462d1e8563 100644 --- a/diff.c +++ b/diff.c @@ -1793,7 +1793,7 @@ static int spawn_prog(const char *pgm, const char **arg) int status; fflush(NULL); - pid = spawnvpe_pipe(pgm, arg, environ, NULL, NULL); + pid = spawnvpe_pipe(pgm, arg, (const char**) environ, NULL, NULL); if (pid < 0) die("unable to fork"); diff --git a/exec_cmd.c b/exec_cmd.c index a9886b87fd..2a8e48b048 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -4,7 +4,6 @@ #include "spawn-pipe.h" #define MAX_ARGS 32 -extern char **environ; static const char *current_exec_path; static const char *builtin_exec_path(void) @@ -138,7 +137,7 @@ int execv_git_cmd(const char **argv) trace_argv_printf(argv, -1, "trace: exec:"); /* execve() can only ever return if it fails */ - execve(git_command, (char **)argv, environ); + execve(git_command, (const char **) argv, (const char **) environ); trace_printf("trace: exec failed: %s\n", strerror(errno)); @@ -247,7 +246,7 @@ int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) trace_argv_printf(argv, -1, "trace: exec:"); - pid = spawnvppe_pipe(cmd, argv, environ, usedpaths, + pid = spawnvppe_pipe(cmd, argv, (const char**) environ, usedpaths, pin, pout); argv[0] = tmp; diff --git a/fetch-pack.c b/fetch-pack.c index e6abf1625a..b6470932fb 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -512,7 +512,7 @@ static int get_pack(int xd[2]) if (read_pack_header(fd[0], &header)) die("protocol error: bad pack header"); - snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", + snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%lu,%lu", ntohl(header.hdr_version), ntohl(header.hdr_entries)); if (ntohl(header.hdr_entries) < unpack_limit) do_keep = 0; diff --git a/index-pack.c b/index-pack.c index 8403c36b63..32e9dd99df 100644 --- a/index-pack.c +++ b/index-pack.c @@ -141,7 +141,7 @@ static void parse_pack_header(void) if (hdr->hdr_signature != htonl(PACK_SIGNATURE)) die("pack signature mismatch"); if (!pack_version_ok(hdr->hdr_version)) - die("pack version %d unsupported", ntohl(hdr->hdr_version)); + die("pack version %lu unsupported", ntohl(hdr->hdr_version)); nr_objects = ntohl(hdr->hdr_entries); use(sizeof(struct pack_header)); diff --git a/merge-index.c b/merge-index.c index fa719cb0b1..1cf4cb5b3f 100644 --- a/merge-index.c +++ b/merge-index.c @@ -48,7 +48,7 @@ static int merge_entry(int pos, const char *path) break; found++; strcpy(hexbuf[stage], sha1_to_hex(ce->sha1)); - sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode)); + sprintf(ownbuf[stage], "%lo", ntohl(ce->ce_mode)); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; } while (++pos < active_nr); diff --git a/pager.c b/pager.c index a55f4e9d1e..4048894734 100644 --- a/pager.c +++ b/pager.c @@ -88,7 +88,7 @@ void setup_pager(void) #else /* spawn the pager */ pager_argv[2] = pager; - pager_pid = spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL); + pager_pid = spawnvpe_pipe(pager_argv[0], pager_argv, (const char**) environ, fd, NULL); if (pager_pid < 0) return; diff --git a/read-cache.c b/read-cache.c index abc41561df..849e8d6b0f 100644 --- a/read-cache.c +++ b/read-cache.c @@ -149,7 +149,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) changed |= DATA_CHANGED; return changed; default: - die("internal error: ce_mode is %o", ntohl(ce->ce_mode)); + die("internal error: ce_mode is %lo", ntohl(ce->ce_mode)); } if (ce->ce_mtime.sec != htonl(st->st_mtime)) changed |= MTIME_CHANGED; diff --git a/receive-pack.c b/receive-pack.c index d3c422be58..94bc99b40d 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -352,7 +352,7 @@ static const char *unpack(void) hdr_err = parse_pack_header(&hdr); if (hdr_err) return hdr_err; - snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", + snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%lu,%lu", ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { diff --git a/run-command.c b/run-command.c index 5964e7d4dd..f208ed45fa 100644 --- a/run-command.c +++ b/run-command.c @@ -14,7 +14,7 @@ int start_command(struct child_process *cmd) int need_in, need_out; int fdin[2] = { -1, -1 }; int fdout[2] = { -1, -1 }; - char **env = environ; + const char **env = (const char **) environ; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { @@ -75,7 +75,7 @@ int start_command(struct child_process *cmd) if (cmd->git_cmd) { cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout); } else { - cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout); + cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, (const char**) env, fdin, fdout); } } if (cmd->pid < 0) { diff --git a/sha1_file.c b/sha1_file.c index 4629fe81a4..1e3cf60ca0 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -425,15 +425,17 @@ static size_t peak_pack_mapped; static size_t pack_mapped; struct packed_git *packed_git; +extern size_t getpagesize(); + void pack_report(void) { fprintf(stderr, "pack_report: getpagesize() = %10" SZ_FMT "\n" "pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n" "pack_report: core.packedGitLimit = %10" SZ_FMT "\n", - (size_t) getpagesize(), - packed_git_window_size, - packed_git_limit); + (unsigned long) getpagesize(), + (unsigned long) packed_git_window_size, + (unsigned long) packed_git_limit); fprintf(stderr, "pack_report: pack_used_ctr = %10u\n" "pack_report: pack_mmap_calls = %10u\n" @@ -443,7 +445,8 @@ void pack_report(void) pack_used_ctr, pack_mmap_calls, pack_open_windows, peak_pack_open_windows, - pack_mapped, peak_pack_mapped); + (unsigned long) pack_mapped, + (unsigned long) peak_pack_mapped); } static int check_packed_git_idx(const char *path, struct packed_git *p) @@ -634,7 +637,6 @@ static int open_packed_git_1(struct packed_git *p) struct pack_header hdr; unsigned char sha1[20]; unsigned char *idx_sha1; - long fd_flag; if (!p->index_data && open_pack_index(p)) return error("packfile %s index unavailable", p->pack_name); @@ -669,13 +671,13 @@ static int open_packed_git_1(struct packed_git *p) if (hdr.hdr_signature != htonl(PACK_SIGNATURE)) return error("file %s is not a GIT packfile", p->pack_name); if (!pack_version_ok(hdr.hdr_version)) - return error("packfile %s is version %u and not supported" + return error("packfile %s is version %lu and not supported" " (try upgrading GIT to a newer version)", p->pack_name, ntohl(hdr.hdr_version)); /* Verify the pack matches its index. */ if (p->num_objects != ntohl(hdr.hdr_entries)) - return error("packfile %s claims to have %u objects" + return error("packfile %s claims to have %lu objects" " while index indicates %u objects", p->pack_name, ntohl(hdr.hdr_entries), p->num_objects); diff --git a/show-index.c b/show-index.c index 57ed9e87b7..6943e4bbb3 100644 --- a/show-index.c +++ b/show-index.c @@ -68,7 +68,7 @@ int main(int argc, char **argv) ntohl(off64[1]); off64_nr++; } - printf("%llu %s (%08x)\n", (unsigned long long) offset, + printf("%llu %s (%08lx)\n", (unsigned long long) offset, sha1_to_hex(entries[i].sha1), ntohl(entries[i].crc)); } diff --git a/spawn-pipe.c b/spawn-pipe.c index c8f0452823..e8872dc0ff 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -1,8 +1,6 @@ #include "git-compat-util.h" #include "spawn-pipe.h" -extern char **environ; - #ifdef __MINGW32__ static char *lookup_prog(const char *dir, const char *cmd, int tryexe) { @@ -193,7 +191,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, qargv = xmalloc((argc+2)*sizeof(char*)); if (!interpr) { quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, env); + pid = spawnve(_P_NOWAIT, prog, qargv, (const char**) env); } else { qargv[0] = interpr; argv[0] = prog; @@ -219,7 +217,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, const char **copy_environ() { - return copy_env(environ); + return copy_env( (const char**)environ); } const char **copy_env(const char **env) diff --git a/unpack-trees.c b/unpack-trees.c index dfd985b0ef..d017f667ce 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -638,7 +638,7 @@ static void show_stage_entry(FILE *o, if (!ce) fprintf(o, "%s (missing)\n", label); else - fprintf(o, "%s%06o %s %d\t%s\n", + fprintf(o, "%s%06lo %s %d\t%s\n", label, ntohl(ce->ce_mode), sha1_to_hex(ce->sha1), From 57bab054a9f7cd82f8889ef4fad58653d89f38fc Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 11 Aug 2007 22:15:39 +0200 Subject: [PATCH 0185/3720] help (msysgit): teach git help to open html from /doc/git/html/ Html pages will be opened using the default Windows application configured for html. This code path is taken for msysgit (mingw). It is assumed that html pages are installed at /doc/git/html. This needs to be ensured by the msysgit superproject to make this patch useful. html pages should be cloned from git.git's main repo. This is the easiest way to get up-to-date documentation, without requiring the complete tool chain to generate them locally. If html pages are not yet there, you can use the following commands to get them: mkdir -p /doc/git/html cd /doc/git/html/ git init git config remote.origin.url git://git.kernel.org/pub/scm/git/git.git git config remote.origin.fetch refs/heads/html:refs/remotes/origin/html git fetch git checkout --track -b html origin/html and update the html documentation with git pull Signed-off-by: Steffen Prohaska --- help.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/help.c b/help.c index 7d59efa50b..e7da8ae430 100644 --- a/help.c +++ b/help.c @@ -180,7 +180,25 @@ static void show_man_page(const char *git_cmd) page = p; } +#ifdef __MINGW32__ + { + char* prefix = "/doc/git/html/"; + int prefix_len = strlen (prefix); + char* suffix = ".html"; + int suffix_len = strlen (suffix); + int page_len = strlen (page); + int htmlpath_len = prefix_len + page_len + suffix_len; + char* htmlpath = xmalloc (htmlpath_len + 1); + strcpy (htmlpath, prefix); + strcpy (htmlpath + prefix_len, page); + strcpy (htmlpath + prefix_len + page_len, suffix); + htmlpath[htmlpath_len] = 0; + /* We need sh here to run shell script /bin/start. */ + execlp("sh", "start", "/bin/start", htmlpath, NULL ); + } +#else execlp("man", "man", page, NULL); +#endif } void help_unknown_cmd(const char *cmd) From fefe8db81717b895dcc10977dc10827c6eaa045f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 11 Aug 2007 00:10:13 +0200 Subject: [PATCH 0186/3720] mergetool: refactored kdiff3 -> KDIFF3 Use shell variable KDIFF3 instead of kdiff3 to call kdiff3. This will be used in detection of the absolute absolute path. --- git-mergetool.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index e6bbb6bbd6..90a69b3465 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -13,6 +13,8 @@ SUBDIRECTORY_OK=Yes . git-sh-setup require_work_tree +KDIFF3=kdiff3 + # Returns true if the mode reflects a symlink is_symlink () { test "$1" = 120000 @@ -191,10 +193,10 @@ merge_file () { case "$merge_tool" in kdiff3) if base_present ; then - (kdiff3 --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \ + ("$KDIFF3" --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \ -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) else - (kdiff3 --auto -L1 "$path (Local)" --L2 "$path (Remote)" \ + ("$KDIFF3" --auto -L1 "$path (Local)" --L2 "$path (Remote)" \ -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1) fi status=$? From 3318ad905e53243dbd59002e4c95106268f763cb Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 11 Aug 2007 00:34:34 +0200 Subject: [PATCH 0187/3720] mergetool: added support for kdiff3 on windows kdiff3's homepage is http://kdiff3.sourceforge.net/. kdiff3 is automatically added to the available mergetools if its path is found in the Windows Registry. The path is taken from the registry. Be sure to set git config core.autocrlf true because kdiff3 seems to follow Windows crlf convention. --- git-mergetool.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index 90a69b3465..ac23891980 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -14,6 +14,7 @@ SUBDIRECTORY_OK=Yes require_work_tree KDIFF3=kdiff3 +KDIFF3SEPARATOR=-- # Returns true if the mode reflects a symlink is_symlink () { @@ -194,10 +195,10 @@ merge_file () { kdiff3) if base_present ; then ("$KDIFF3" --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \ - -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) + -o "$path" $KDIFF3SEPERATOR "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) else ("$KDIFF3" --auto -L1 "$path (Local)" --L2 "$path (Remote)" \ - -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1) + -o "$path" $KDIFF3SEPERATOR "$LOCAL" "$REMOTE" > /dev/null 2>&1) fi status=$? remove_backup @@ -321,6 +322,11 @@ if test -z "$merge_tool" ; then merge_tool_candidates="kdiff3 $merge_tool_candidates" fi fi + regentry="$(REG QUERY 'HKEY_LOCAL_MACHINE\SOFTWARE\KDiff3\diff-ext' 2>/dev/null)" && { + KDIFF3=$(echo "$regentry" | grep diffcommand | cut -f 3) + KDIFF3SEPARATOR= + merge_tool_candidates="$merge_tool_candidates kdiff3" + } if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then merge_tool_candidates="$merge_tool_candidates emerge" fi @@ -332,10 +338,12 @@ if test -z "$merge_tool" ; then for i in $merge_tool_candidates; do if test $i = emerge ; then cmd=emacs + elif test $i = kdiff3 ; then + cmd="$KDIFF3" else cmd=$i fi - if type $cmd > /dev/null 2>&1; then + if type "$cmd" > /dev/null 2>&1; then merge_tool=$i break fi @@ -347,7 +355,13 @@ if test -z "$merge_tool" ; then fi case "$merge_tool" in - kdiff3|tkdiff|meld|xxdiff|vimdiff|gvimdiff|opendiff) + kdiff3) + if ! type "$KDIFF3" > /dev/null 2>&1; then + echo "The merge tool $merge_tool is not available" + exit 1 + fi + ;; + tkdiff|meld|xxdiff|vimdiff|gvimdiff|opendiff) if ! type "$merge_tool" > /dev/null 2>&1; then echo "The merge tool $merge_tool is not available" exit 1 From 56be985fe902a4af8c7f0bbe4541ef783ead827f Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Tue, 14 Aug 2007 09:48:39 +0200 Subject: [PATCH 0188/3720] Avoid calling signal(SIGPIPE, ..) for MinGW builds. SIGPIPE isn't supported in MinGW. Signed-off-by: Marius Storm-Olsen --- builtin-verify-tag.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index dfcfcd0455..5c1314d071 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -100,9 +100,11 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) i++; } +#ifndef __MINGW32__ /* sometimes the program was terminated because this signal * was received in the process of writing the gpg input: */ signal(SIGPIPE, SIG_IGN); +#endif while (i < argc) if (verify_tag(argv[i++], verbose)) had_error = 1; From 65b356f555a716d9f753e58911da2017f3d1c2fc Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 13 Aug 2007 08:04:14 +0200 Subject: [PATCH 0189/3720] mergetool: converting backslashes in kdiff3 path from Windows registry Backslashes are converted to slashes right after the Windows registry returned a path. This is needed to avoid problems with shell expansion. Signed-off-by: Steffen Prohaska --- git-mergetool.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index ac23891980..e7d745062b 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -323,7 +323,7 @@ if test -z "$merge_tool" ; then fi fi regentry="$(REG QUERY 'HKEY_LOCAL_MACHINE\SOFTWARE\KDiff3\diff-ext' 2>/dev/null)" && { - KDIFF3=$(echo "$regentry" | grep diffcommand | cut -f 3) + KDIFF3=$(echo "$regentry" | grep diffcommand | cut -f 3 | sed -e 's@\\@/@g') KDIFF3SEPARATOR= merge_tool_candidates="$merge_tool_candidates kdiff3" } From 1a896a59003da71410fe34cf5687832d1f2a6797 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Tue, 14 Aug 2007 13:48:56 -0400 Subject: [PATCH 0190/3720] Correct logic from merge to fix t1020-subdirectory.sh. Some logic was lost from the merge from git.git. Signed-off-by: Mike Pape --- connect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index 9f51e8dcc8..ea810c4df9 100644 --- a/connect.c +++ b/connect.c @@ -525,7 +525,8 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) ) { protocol = PROTO_SSH; *path++ = '\0'; - } + } else + path = host; } else path = end; From d1f83218dce62affd1d7a82a9e654cca08dade9c Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Wed, 15 Aug 2007 13:18:20 -0400 Subject: [PATCH 0191/3720] Hardlinks are not supported in MSys so we disable them. We do not want the default to be hardlinks for local clones and we show a warning if the user tries to use -l. Signed-off-by: Mike Pape --- Makefile | 9 +++++++++ git-clone.sh | 5 ++++- t/Makefile | 4 ++++ t/t5701-clone-local.sh | 7 +++++++ t/test-lib.sh | 2 ++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 36fa094462..456681b27c 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,9 @@ all: # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link. # Enable it on Windows. By default, symrefs are still used. # +# Define NO_HARDLINKS if you want to disable hard linking in git clone. +# Enable it on Windows. +# # Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability # tests. These tests take up a significant amount of the total test time # but are not needed unless you plan to talk to SVN repos. @@ -482,6 +485,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_PREAD=YesPlease NO_OPENSSL=YesPlease NO_SYMLINK_HEAD=YesPlease + NO_HARDLINKS=YesPlease NO_IPV6=YesPlease NO_ETC_PASSWD=YesPlease NO_SETENV=YesPlease @@ -724,6 +728,10 @@ ifdef ASCIIDOC8 export ASCIIDOC8 endif +ifdef NO_HARDLINKS + export NO_HARDLINKS +endif + # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@ -799,6 +807,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ + -e 's/@@NO_HARDLINKS@@/$(NO_HARDLINKS)/g' \ $@.sh >$@+ && \ chmod +x $@+ && \ mv $@+ $@ diff --git a/git-clone.sh b/git-clone.sh index 2c0164aafe..72435b03aa 100644 --- a/git-clone.sh +++ b/git-clone.sh @@ -99,6 +99,7 @@ origin_override= use_separate_remote=t depth= no_progress= +test "@@NO_HARDLINKS@@" && use_local_hardlink=no test -t 1 || no_progress=--no-progress while case "$#,$1" in @@ -109,7 +110,9 @@ while *,--na|*,--nak|*,--nake|*,--naked|\ *,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;; *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) - use_local_hardlink=yes ;; + (test "@@NO_HARDLINKS@@" && + echo >&2 "Warning: -l asked but hardlinks are not supported") || + use_local_hardlink=yes ;; *,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\ *,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks) use_local_hardlink=no ;; diff --git a/t/Makefile b/t/Makefile index f8e396c108..2b808f96bb 100644 --- a/t/Makefile +++ b/t/Makefile @@ -18,6 +18,10 @@ ifdef NO_SYMLINKS GIT_TEST_OPTS += --no-symlinks endif +ifdef NO_HARDLINKS + GIT_TEST_OPTS += --no-hardlinks +endif + all: $(T) clean $(T): diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index a3026ec4fc..d2f55ebfbc 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -3,6 +3,13 @@ test_description='test local clone' . ./test-lib.sh +if test "$no_hardlinks" +then + say 'Hard links not supported, skipping tests.' + test_done + exit +fi + D=`pwd` test_expect_success 'preparing origin repository' ' diff --git a/t/test-lib.sh b/t/test-lib.sh index 6081d172ab..143d95daca 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -89,6 +89,8 @@ do shift ;; --no-symlinks) no_symlinks=t; shift ;; + --no-hardlinks) + no_hardlinks=t; shift ;; *) break ;; esac From a0b4827288741c7939e40e269aa8298454a56eff Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Thu, 16 Aug 2007 21:16:48 +0200 Subject: [PATCH 0192/3720] Revert "Correct logic from merge to fix t1020-subdirectory.sh." This reverts commit 1a896a59003da71410fe34cf5687832d1f2a6797. The patch had an adverse effect on fetching with the git+ssh protocol, giving me the following errors Pseudo-terminal will not be allocated because stdin is not a terminal. ssh: ': no address associated with hostname. fatal: The remote end hung up unexpectedly Cannot get the repository state from git+ssh:// and [0: 172.20.1.78]: errno=Invalid argument [1: 192.168.1.3]: errno=Bad file descriptor [2: 192.168.35.1]: errno=Bad file descriptor [3: 192.168.150.1]: errno=Bad file descriptor fatal: unable to connect a socket (Bad file descriptor) Cannot get the repository state from git:// Signed-off-by: Marius Storm-Olsen --- connect.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/connect.c b/connect.c index ea810c4df9..9f51e8dcc8 100644 --- a/connect.c +++ b/connect.c @@ -525,8 +525,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) ) { protocol = PROTO_SSH; *path++ = '\0'; - } else - path = host; + } } else path = end; From 6c75a2449182af7153d00c06bcda853258a10b21 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 11:53:24 +0200 Subject: [PATCH 0193/3720] Do not hard-code paths for the shell and perl. The reason to set SHELL_PATH and PERL_PATH was that 'make' failed to execute /bin/sh some-script It turns out that different MinGW/MSYS environments have different levels of support for this construct, so use the default and let the user override the settings in config.mak if the defaults don't work. --- Makefile | 2 -- README.MinGW | 7 +++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8127a5569d..bd25c8abf6 100644 --- a/Makefile +++ b/Makefile @@ -475,8 +475,6 @@ ifeq ($(uname_S),IRIX64) BASIC_LDFLAGS += -L/usr/lib32 endif ifneq (,$(findstring MINGW,$(uname_S))) - SHELL_PATH = $(shell cd /bin && pwd -W)/sh - PERL_PATH = $(shell cd /bin && pwd -W)/perl NO_MMAP=YesPlease NO_PREAD=YesPlease NO_OPENSSL=YesPlease diff --git a/README.MinGW b/README.MinGW index 436d7b7849..74eb104c2c 100644 --- a/README.MinGW +++ b/README.MinGW @@ -31,6 +31,13 @@ In order to compile this code you need: libiconv-1.9.2-1-{lib,bin,lib}.zip (for git-am, from http://gnuwin32.sourceforge.net/packages/libiconv.htm) +I am using these settings in config.mak to have pointers to the right tools: + +TCL_PATH=tclsh84 +TCLTK_PATH=wish84 +SHELL_PATH=D:/MSYS/1.0/bin/sh +PERL_PATH=D:/MSYS/1.0/bin/perl + STATUS ------ From a9601507cf0bc6d987117dfcd0e3d98873f4ab61 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 12:27:54 +0200 Subject: [PATCH 0194/3720] Move MinGW specific declaration of mkstmp() up to avoid warnings. The declaration is needed in the xmkstmp() implementation. --- git-compat-util.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git-compat-util.h b/git-compat-util.h index 219ac871b4..75b2a4bc9b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -54,6 +54,8 @@ #include #include #include +#else +int mkstemp (char *__template); #endif #include #include @@ -435,7 +437,6 @@ int kill(pid_t pid, int sig); unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); -int mkstemp (char *__template); int gettimeofday(struct timeval *tv, void *tz); int pipe(int filedes[2]); From 94be0afa317c2cd54456652970cfefa7767b464f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 13:16:01 +0200 Subject: [PATCH 0195/3720] Provide a definition of SIGPIPE. --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index 75b2a4bc9b..22a53d3668 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -431,6 +431,7 @@ typedef int pid_t; #define SIGKILL 0 #define SIGCHLD 0 #define SIGALRM 0 +#define SIGPIPE 0 #define ECONNABORTED 0 int kill(pid_t pid, int sig); From 94e7a6b7b4d2b8901b836a398e1d3733c64112e1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 17 Aug 2007 14:50:29 +0200 Subject: [PATCH 0196/3720] Revert fa807fcb: 'Revert "Makefile: remove $foo when $foo.exe...' It works in msysgit, so there is no reason why we should not remove the scripted versions. Especially since some tests were failing for the sole reason that _not_ the builtin, but the script was executed. Signed-off-by: Johannes Schindelin --- Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 456681b27c..62407ad0be 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # The default target of this Makefile is... -all: +all:: # Define V=1 to have a more verbose compile. # @@ -762,9 +762,12 @@ export TAR INSTALL DESTDIR SHELL_PATH ### Build rules -all: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) +all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';) +endif -all: +all:: ifndef NO_TCLTK $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) all endif @@ -993,7 +996,7 @@ endif 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) +all:: $(TEST_PROGRAMS) # GNU make supports exporting all variables by "export" without parameters. # However, the environment gets quite big, and some programs have problems @@ -1045,6 +1048,9 @@ endif '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ fi $(foreach p,$(BUILT_INS), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) +endif install-doc: $(MAKE) -C Documentation install From 009ab81675846be538bd337d9addd9965d2925aa Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 15:14:57 +0200 Subject: [PATCH 0197/3720] Avoid spawning 'ls' for each directory that is passed to the cpio emulator. We assume that the file names are passed in using find -depth so that a directory is listed after its contents. --- cpio.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cpio.sh b/cpio.sh index 2816e34851..df5f64c14c 100644 --- a/cpio.sh +++ b/cpio.sh @@ -24,16 +24,24 @@ while test $# -gt 0; do shift done +prev= + filterdirs() { while read f; do if test -d "$f"; then # list only empty directories - if test -z "$(ls -A "$f")"; then - echo "$f" - fi + # here we assume that directories are listed after + # its files (aka 'find -depth'), hence, a directory + # that is not empty will be a leading sub-string + # of the preceding entry + case "$prev" in + "$f"/* ) ;; + *) echo "$f";; + esac else echo "$f" fi + prev="$f" done } From 942afeb88b16e1be0b653114491668b2140ca5e1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 18:40:36 +0200 Subject: [PATCH 0198/3720] Work around a Windows oddity when a pipe with no reader is written to. The first WriteFile() returns ERROR_BROKEN_PIPE, subsequent WriteFile()s return ERROR_NO_DATA, which is not translated to EPIPE, but EINVAL. Hmpf! --- write_or_die.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/write_or_die.c b/write_or_die.c index e125e11d3b..40b046acb0 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -34,7 +34,16 @@ void maybe_flush_or_die(FILE *f, const char *desc) return; } if (fflush(f)) { +#ifndef __MINGW32__ if (errno == EPIPE) +#else + /* + * On Windows, EPIPE is returned only by the first write() + * after the reading end has closed its handle; subsequent + * write()s return EINVAL. + */ + if (errno == EPIPE || errno == EINVAL) +#endif exit(0); die("write failure on %s: %s", desc, strerror(errno)); } From 331406ad302671f696f4c624737acfede7bf1d04 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Fri, 17 Aug 2007 19:18:09 -0400 Subject: [PATCH 0199/3720] Correct connect logic to allow for Windows C: paths. We need to add logic for windows to allow C: and not assume the : means it's another protocol. Signed-off-by: Mike Pape --- connect.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/connect.c b/connect.c index 9f51e8dcc8..1c92df0f21 100644 --- a/connect.c +++ b/connect.c @@ -518,13 +518,18 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) path = strchr(end, c); if (path) { - if (c == ':' + if (c == ':') { #ifdef __MINGW32__ - && path - end > 1 /* host must have at least 2 chars to catch DOS C:/path */ + /* host must have at least 2 chars to + * catch DOS C:/path */ + if (path - end > 1) { +#endif + protocol = PROTO_SSH; + *path++ = '\0'; +#ifdef __MINGW32__ + } else + path = end; #endif - ) { - protocol = PROTO_SSH; - *path++ = '\0'; } } else path = end; From 20e93f53e3a220018c62e0055a083af6079b8a2c Mon Sep 17 00:00:00 2001 From: Johannes Schmidt-Ehrenberg Date: Mon, 13 Aug 2007 19:00:39 +0200 Subject: [PATCH 0200/3720] mergetool: fixed parsing of registry entry for kdiff3 The old code failed on Windows Vista. The output of reg.exe or something else may be a bit different. This patch improves the parsing code to be more robust. Signed-off-by: Steffen Prohaska --- git-mergetool.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index e7d745062b..54f6d58a84 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -323,7 +323,7 @@ if test -z "$merge_tool" ; then fi fi regentry="$(REG QUERY 'HKEY_LOCAL_MACHINE\SOFTWARE\KDiff3\diff-ext' 2>/dev/null)" && { - KDIFF3=$(echo "$regentry" | grep diffcommand | cut -f 3 | sed -e 's@\\@/@g') + KDIFF3=$(echo "$regentry" | grep diffcommand | awk -F 'REG_SZ' '{ print $2 }' | sed -e 's/^ *//'| sed -e 's@\\@/@g') KDIFF3SEPARATOR= merge_tool_candidates="$merge_tool_candidates kdiff3" } From fce4254719a628b469c7a8c1a2ceb025e630bf2a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 20 Aug 2007 16:36:58 +0200 Subject: [PATCH 0201/3720] Fix an infinite loop in setup_git_directory_gently(). When a git command was invoked outside any git directory, it would not terminate. --- setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.c b/setup.c index d575529ac9..404191ab8f 100644 --- a/setup.c +++ b/setup.c @@ -302,7 +302,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } chdir(".."); do { - if (!offset) { + if (offset <= minoffset) { if (nongit_ok) { if (chdir(cwd)) die("Cannot come back to cwd"); From ae3d370abf6ae61f5b15d3ad5703023080124872 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Fri, 24 Aug 2007 08:36:30 +0200 Subject: [PATCH 0202/3720] Add patch from Linus, to make write-tree read the configuration, in case it datestamps are so close that it needs to ce_smudge_racily_clean_entry(), thus read the content of the file and compare. The core.autocrlf value is needed in this case. Signed-off-by: Marius Storm-Olsen --- builtin-write-tree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-write-tree.c b/builtin-write-tree.c index 88f34ba7d6..b89d02efec 100644 --- a/builtin-write-tree.c +++ b/builtin-write-tree.c @@ -72,6 +72,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) const char *prefix = NULL; unsigned char sha1[20]; + git_config(git_default_config); while (1 < argc) { const char *arg = argv[1]; if (!strcmp(arg, "--missing-ok")) From dd56555ea5cd03958dc2f987f2776efbab571452 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Thu, 23 Aug 2007 22:03:35 +0200 Subject: [PATCH 0203/3720] Add a trace to more easily show that the index has been smudged. Signed-off-by: Marius Storm-Olsen --- read-cache.c | 1 + 1 file changed, 1 insertion(+) diff --git a/read-cache.c b/read-cache.c index 84c6b47eb8..23d16a40ef 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1104,6 +1104,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) * for "frotz" stays 6 which does not match the filesystem. */ ce->ce_size = htonl(0); + trace_printf("trace: index: Index object for '%s' smudged due to being racily clean\n", ce->name); } } From 6e6b01d5d308a9bbb5d73cd9272d8736039d83a2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 29 Aug 2007 13:34:54 +0200 Subject: [PATCH 0204/3720] Add a primitive implementation for getppid(). --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index 22a53d3668..1ba499f750 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -483,6 +483,7 @@ int mingw_rename(const char*, const char*); #define setlinebuf(x) #define fsync(x) 0 +#define getppid() 1 extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From 14e86ec37e13f6018513c630f4b8b54096e794f0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 29 Aug 2007 14:49:47 +0200 Subject: [PATCH 0205/3720] Use 'pwd -W' as reference directory. git does not know about the notation /x/dir/ec/tory that MSYS uses instead of x:/dir/ec/tory; hence, when git's notion of an absolute path is compared to the shell's notion, the shell must produce the x:/ kind of path. --- t/t0001-init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index b14b3ec394..ca5b631012 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -97,7 +97,7 @@ test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' ' mkdir git-dir-wt-1.git && GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init ) && - check_config git-dir-wt-1.git false "$(pwd)" + check_config git-dir-wt-1.git false "$(pwd -W)" ' test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' ' From 205d0cb456f7d253f6fcd0566528c1d2796f0be5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 29 Aug 2007 14:50:58 +0200 Subject: [PATCH 0206/3720] Use /usr/bin/find instead of plain find. --- t/t9300-fast-import.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 0595041af5..a64f78f5a0 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -880,7 +880,7 @@ INPUT_END test_expect_success \ 'O: blank lines not necessary after other commands' \ 'git-fast-import actual && git diff expect actual' From 194c1dbb5a04e29937b87d477a16927fa2c3be62 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Aug 2007 14:16:46 +0100 Subject: [PATCH 0207/3720] Provide git_exit() for MinGW Apparently, MinGW's exit function has problems with negative exit codes. Substitute them by 1. This fixes at least t1300, which failed because the exit code of git-config with an invalid file was 0. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 9 +++++++++ git-compat-util.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index ca3ae4cb06..6632192690 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -322,3 +322,12 @@ int mingw_socket(int domain, int type, int protocol) } return s; } + +#undef exit +int git_exit(int code) +{ + if (code < 0) + exit(1); + exit(code); +} + diff --git a/git-compat-util.h b/git-compat-util.h index ddafec997f..9e075b715c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -472,6 +472,9 @@ int mingw_socket(int domain, int type, int protocol); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +extern __attribute__((noreturn)) int git_exit(int code); +#define exit git_exit + #endif /* __MINGW32__ */ #endif From b01b123d9dea5658a5e8eb8d392c5cdbe23256a5 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Wed, 29 Aug 2007 15:35:00 +0200 Subject: [PATCH 0208/3720] Fix error 'fatal: Not a git repository' on Vista Define __USE_MINGW_ACCESS, which changes access( ..., X_OK ) into F_OK. Signed-off-by: Dmitry Kakurin gmail.com> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f828f6cd12..9669817bf4 100644 --- a/Makefile +++ b/Makefile @@ -493,7 +493,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRTOUMAX = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe From fce2bf8842e8224822619afabff1bfcfc3546436 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 17 Aug 2007 14:50:29 +0200 Subject: [PATCH 0209/3720] Revert fa807fcb: 'Revert "Makefile: remove $foo when $foo.exe...' It works in msysgit, so there is no reason why we should not remove the scripted versions. Especially since some tests were failing for the sole reason that _not_ the builtin, but the script was executed. Signed-off-by: Johannes Schindelin --- Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 9669817bf4..bc8e9d2125 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # The default target of this Makefile is... -all: +all:: # Define V=1 to have a more verbose compile. # @@ -752,9 +752,12 @@ export TAR INSTALL DESTDIR SHELL_PATH ### Build rules -all: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) +all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';) +endif -all: +all:: ifndef NO_TCLTK $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) all endif @@ -982,7 +985,7 @@ endif 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) +all:: $(TEST_PROGRAMS) # GNU make supports exporting all variables by "export" without parameters. # However, the environment gets quite big, and some programs have problems @@ -1030,6 +1033,9 @@ endif '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ fi $(foreach p,$(BUILT_INS), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) +endif install-doc: $(MAKE) -C Documentation install From 5464a3f4b7fdc844253b5d64b0b311fde31ee1b2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Aug 2007 17:43:02 +0100 Subject: [PATCH 0210/3720] t5701: "wc -l" may add whitespace Signed-off-by: Johannes Schindelin --- t/t5701-clone-local.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index d2f55ebfbc..7e7019fa31 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -54,8 +54,7 @@ test_expect_success 'With -no-hardlinks, local will make a copy' ' cd "$D" && git clone --bare --no-hardlinks x w && cd w && - linked=$(find objects -type f ! -links 1 | wc -l) && - test "$linked" = 0 + test $(find objects -type f ! -links 1 | wc -l) = 0 ' test_expect_success 'Even without -l, local will make a hardlink' ' @@ -63,8 +62,7 @@ test_expect_success 'Even without -l, local will make a hardlink' ' rm -fr w && git clone -l --bare x w && cd w && - copied=$(find objects -type f -links 1 | wc -l) && - test "$copied" = 0 + test $(find objects -type f -links 1 | wc -l) = 0 ' test_done From 685268d9a1d4db52c62e022a7543a5c092ac8fec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Aug 2007 17:57:08 +0100 Subject: [PATCH 0211/3720] t5701: skip hardlink test Signed-off-by: Johannes Schindelin --- t/t5701-clone-local.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index 7e7019fa31..e97f435fec 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -57,6 +57,10 @@ test_expect_success 'With -no-hardlinks, local will make a copy' ' test $(find objects -type f ! -links 1 | wc -l) = 0 ' +say "hardlinks not supported, skipping tests." +test_done +exit 0 + test_expect_success 'Even without -l, local will make a hardlink' ' cd "$D" && rm -fr w && From a19cff248ece3693f5dc6ad75a70a3e68606a1f9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Sep 2007 17:42:54 +0100 Subject: [PATCH 0212/3720] verify-tag: also grok CR/LFs in the tag signature On some people's favorite platform, gpg outputs signatures with CR/LF line endings. So verify-tag has to play nice with them. Signed-off-by: Johannes Schindelin --- builtin-verify-tag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index 5c1314d071..8cfefcf523 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -35,7 +35,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose) /* find the length without signature */ len = 0; - while (len < size && prefixcmp(buf + len, PGP_SIGNATURE "\n")) { + while (len < size && prefixcmp(buf + len, PGP_SIGNATURE)) { eol = memchr(buf + len, '\n', size - len); len += eol ? eol - (buf + len) + 1 : size - len; } From 7734ad404c48ea376fed1ce5e9e04f72ec4cb0bd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Sep 2007 17:36:47 +0100 Subject: [PATCH 0213/3720] MinGW: Convert CR/LF to LF in tag signatures On Windows, gpg outputs CR/LF signatures. But since the tag messages are already stripped of the CR by stripspace(), it is arguably nicer to do the same for the tag signature. Actually, this patch does not look for CR/LF, but strips all CRs from the signature. Signed-off-by: Johannes Schindelin --- builtin-tag.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/builtin-tag.c b/builtin-tag.c index d6d38ad123..547f0ba224 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -229,6 +229,20 @@ static ssize_t do_sign(char *buffer, size_t size, size_t max) if (len == max - size) return error("could not read the entire signature from gpg."); +#ifdef __MINGW32__ + /* strip CR from the line endings */ + { + int i, j; + for (i = j = 0; i < len; i++) + if (buffer[size + i] != '\r') { + if (i != j) + buffer[size + j] = buffer[size + i]; + j++; + } + len = j; + } +#endif + return size + len; } From b9dcb2cbe55afa21af7eed9f49e319b183954748 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Sep 2007 19:55:09 +0100 Subject: [PATCH 0214/3720] Fix cpio for CR/LF line endings Under certain circumstances (I did not find out the complete details, but it happens when running the tests), the filterdirs() function in cpio outputs CR/LF. Since tar does not like that, the command failed. So strip out all CRs when filtering the directories. Signed-off-by: Johannes Schindelin --- cpio.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cpio.sh b/cpio.sh index 2816e34851..432903813b 100644 --- a/cpio.sh +++ b/cpio.sh @@ -44,6 +44,7 @@ o) p) test -z "$null" || die "cpio: cannot use -0 in pass-through mode" filterdirs | + tr -d '\r' | tar --create --file=- --files-from=- | tar --extract --directory="$dir" --file=- ;; From 59f8c189a5d582d5eef28ca4021d04087dff2eff Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 23 Aug 2007 10:18:54 -0700 Subject: [PATCH 0215/3720] Fix racy-git handling in git-write-tree. After git-write-tree finishes computing the tree, it updates the index so that later operations can take advantage of fully populated cache tree. However, anybody writing the index file has to mark the entries that are racily clean. For each entry whose cached lstat(3) data in the index exactly matches what is obtained from the filesystem, if the timestamp on the index file was the same or older than the modification timestamp of the file, the blob contents and the work tree file, after convert_to_git(), need to be compared, and if they are different, its index entry needs to be marked not to match the lstat(3) data from the filesystem. In order for this to work, convert_to_git() needs to work correctly, which in turn means you need to read the config file to get the settings of core.crlf and friends. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- t/t0023-crlf-am.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 t/t0023-crlf-am.sh diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh new file mode 100755 index 0000000000..6f8a4347d5 --- /dev/null +++ b/t/t0023-crlf-am.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +test_description='Test am with auto.crlf' + +. ./test-lib.sh + +cat >patchfile <<\EOF +From 38be10072e45dd6b08ce40851e3fca60a31a340b Mon Sep 17 00:00:00 2001 +From: Marius Storm-Olsen +Date: Thu, 23 Aug 2007 13:00:00 +0200 +Subject: test1 + +--- + foo | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + create mode 100644 foo + +diff --git a/foo b/foo +new file mode 100644 +index 0000000000000000000000000000000000000000..5716ca5987cbf97d6bb54920bea6adde242d87e6 +--- /dev/null ++++ b/foo +@@ -0,0 +1 @@ ++bar +EOF + +test_expect_success 'setup' ' + + git config core.autocrlf true && + echo foo >bar && + git add bar && + test_tick && + git commit -m initial + +' + +test_expect_success 'am' ' + + git am --binary -3 Date: Tue, 4 Sep 2007 02:00:46 +0100 Subject: [PATCH 0216/3720] t7004: work around weird quoting issue with MSys It seems to be impossible to pass the _string_ '*a*' if there is _any_ file in the current directory whose name contains the letter 'a'. So remove all such files for the test that needs to pass that string. Signed-off-by: Johannes Schindelin --- t/t7004-tag.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 2ac0003f9e..2aa663e622 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -185,8 +185,9 @@ cba EOF test_expect_success \ 'listing tags with substring as pattern must print those matching' ' - git-tag -l "*a*" > actual && - git diff expect actual + rm *a* && + git-tag -l "*a*" > current && + git diff expect current ' cat >expect < Date: Tue, 4 Sep 2007 02:01:52 +0100 Subject: [PATCH 0217/3720] t0001: fix test on MinGW Another instance where we need the "-W" parameter to "pwd". Signed-off-by: Johannes Schindelin --- t/t0001-init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index b14b3ec394..ca5b631012 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -97,7 +97,7 @@ test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' ' mkdir git-dir-wt-1.git && GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init ) && - check_config git-dir-wt-1.git false "$(pwd)" + check_config git-dir-wt-1.git false "$(pwd -W)" ' test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' ' From 54d99a7724a0c7fb53bcdc7d850034e9890a0138 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 Sep 2007 02:02:27 +0100 Subject: [PATCH 0218/3720] fast-import: fix compilation on MinGW MinGW does not have getppid(). So do not print it. Signed-off-by: Johannes Schindelin --- fast-import.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fast-import.c b/fast-import.c index 078079d404..1d116e7878 100644 --- a/fast-import.c +++ b/fast-import.c @@ -392,7 +392,9 @@ static void write_crash_report(const char *err) fprintf(rpt, "fast-import crash report:\n"); fprintf(rpt, " fast-import process: %d\n", getpid()); +#ifndef __MINGW32__ fprintf(rpt, " parent process : %d\n", getppid()); +#endif fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL)); fputc('\n', rpt); From d23130a5fb430c54bb928dcd4446fd98a2a9173d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 Sep 2007 02:03:55 +0100 Subject: [PATCH 0219/3720] git-compat-util.h: declare mkstemp() before use On MinGW, we roll our own version of mkstemp(). Since xmkstemp() uses it, we need to declare it before that. Signed-off-by: Johannes Schindelin --- git-compat-util.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-compat-util.h b/git-compat-util.h index f817c28164..ba5a1a1018 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -314,6 +314,9 @@ static inline FILE *xfdopen(int fd, const char *mode) return stream; } +#ifdef __MINGW32__ +int mkstemp (char *__template); +#endif static inline int xmkstemp(char *template) { int fd; @@ -435,7 +438,6 @@ int kill(pid_t pid, int sig); unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); -int mkstemp (char *__template); int gettimeofday(struct timeval *tv, void *tz); int pipe(int filedes[2]); From 9c792c5545415dfcbb60f819b9555bbe874a508c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 Sep 2007 02:18:52 +0100 Subject: [PATCH 0220/3720] Fix t3200 on MinGW Since we try to launch the webbrowser with "git --help", one test in t3200 would always try to open a window with the man page for git-branch. Suppress that test for now. Signed-off-by: Johannes Schindelin --- t/t3200-branch.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index a891fa47d3..029f19d6fa 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -17,6 +17,7 @@ test_expect_success \ git-commit -m "Initial commit." && HEAD=$(git rev-parse --verify HEAD)' +true || test_expect_failure \ 'git branch --help should not have created a bogus branch' \ 'git branch --help /dev/null 2>/dev/null || : From 0cce83445cb03b9ae93c2f7f3427e0ca2063dc73 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Mon, 3 Sep 2007 20:40:26 +0200 Subject: [PATCH 0221/3720] Add a new lstat and fstat implementation based on Win32 API This gives us a significant speedup when adding, committing and stat'ing files. Also, since Windows doesn't really handle symlinks, we let stat just uses lstat. We also need to replace fstat, since our implementation and the standard stat() functions report slightly different timestamps, possibly due to timezones. We simply report UTC in our implementation, and do our FILETIME to time_t conversion based on the document at http://support.microsoft.com/kb/167296. With Moe's repo structure (100K files in 100 dirs, containing 2-4 bytes) mkdir bummer && cd bummer; for ((i=0;i<100;i++)); do mkdir $i && pushd $i; for ((j=0;j<1000;j++)); do echo "$j" >$j; done; popd; done We get the following performance boost: With normal lstat & stat Custom lstat/fstat ------------------------ ------------------------ Command: git init Command: git init ------------------------ ------------------------ real 0m 0.047s real 0m 0.063s user 0m 0.031s user 0m 0.015s sys 0m 0.000s sys 0m 0.015s ------------------------ ------------------------ Command: git add . Command: git add . ------------------------ ------------------------ real 0m19.390s real 0m12.031s 1.6x user 0m 0.015s user 0m 0.031s sys 0m 0.030s sys 0m 0.000s ------------------------ ------------------------ Command: git commit -a.. Command: git commit -a.. ------------------------ ------------------------ real 0m30.812s real 0m16.875s 1.8x user 0m 0.015s user 0m 0.015s sys 0m 0.000s sys 0m 0.015s ------------------------ ------------------------ 3x Command: git-status 3x Command: git-status ------------------------ ------------------------ real 0m11.860s real 0m 5.266s 2.2x user 0m 0.015s user 0m 0.015s sys 0m 0.015s sys 0m 0.015s real 0m11.703s real 0m 5.234s user 0m 0.015s user 0m 0.015s sys 0m 0.000s sys 0m 0.000s real 0m11.672s real 0m 5.250s user 0m 0.031s user 0m 0.015s sys 0m 0.000s sys 0m 0.000s ------------------------ ------------------------ Command: git commit... Command: git commit... (single file) (single file) ------------------------ ------------------------ real 0m14.234s real 0m 7.735s 1.8x user 0m 0.015s user 0m 0.031s sys 0m 0.000s sys 0m 0.000s Signed-off-by: Marius Storm-Olsen --- compat/mingw.c | 107 ++++++++++++++++++++++++++++++++++++++++++++-- git-compat-util.h | 8 ++++ 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 7711a3fb39..20eadd2334 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -23,12 +23,81 @@ int fchmod(int fildes, mode_t mode) return -1; } -int lstat(const char *file_name, struct stat *buf) +static inline time_t filetime_to_time_t(const FILETIME *ft) +{ + long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; + winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ + winTime /= 10000000; /* Nano to seconds resolution */ + return (time_t)winTime; +} + +extern int _getdrive( void ); +/* We keep the do_lstat code in a separate function to avoid recursion. + * When a path ends with a slash, the stat will fail with ENOENT. In + * this case, we strip the trailing slashes and stat again. + */ +static int do_lstat(const char *file_name, struct stat *buf) +{ + WIN32_FILE_ATTRIBUTE_DATA fdata; + + if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) { + int fMode = S_IREAD; + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + fMode |= S_IFDIR; + else + fMode |= S_IFREG; + if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + fMode |= S_IWRITE; + + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = fMode; + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + errno = 0; + return 0; + } + + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_SHARING_BUFFER_EXCEEDED: + errno = EACCES; + break; + case ERROR_BUFFER_OVERFLOW: + errno = ENAMETOOLONG; + break; + case ERROR_NOT_ENOUGH_MEMORY: + errno = ENOMEM; + break; + case ERROR_INVALID_NAME: + errno = EFAULT; + break; + default: + errno = ENOENT; + break; + } + return -1; +} + +/* We provide our own lstat/fstat functions, since the provided + * lstat/fstat functions are so slow. These stat functions are + * tailored for Git's usage (read: fast), and are not meant to be + * complete. Note that Git stat()s are redirected to git_lstat() + * too, since Windows doesn't really handle symlinks that well. + */ +int git_lstat(const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!stat(file_name, buf)) + if (!do_lstat(file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -36,6 +105,7 @@ int lstat(const char *file_name, struct stat *buf) */ if (errno != ENOENT) return -1; + namelen = strlen(file_name); if (namelen && file_name[namelen-1] != '/') return -1; @@ -43,9 +113,40 @@ int lstat(const char *file_name, struct stat *buf) --namelen; if (!namelen || namelen >= PATH_MAX) return -1; + memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return stat(alt_name, buf); + return do_lstat(alt_name, buf); +} + +int git_fstat(int fd, struct stat *buf) +{ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + BY_HANDLE_FILE_INFORMATION fdata; + + if (fh != INVALID_HANDLE_VALUE && GetFileInformationByHandle(fh, &fdata)) { + int fMode = S_IREAD; + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + fMode |= S_IFDIR; + else + fMode |= S_IFREG; + if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + fMode |= S_IWRITE; + + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = fMode; + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + return 0; + } + errno = EBADF; + return -1; } /* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ diff --git a/git-compat-util.h b/git-compat-util.h index 1ba499f750..bdc2e3f5fc 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -488,6 +488,14 @@ int mingw_rename(const char*, const char*); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +/* Use git_lstat() instead of lstat()/stat() and + * git_fstat() instead of fstat() on Windows + */ +int git_lstat(const char *file_name, struct stat *buf); +int git_fstat(int fd, struct stat *buf); +#define lstat(x,y) git_lstat(x,y) +#define stat(x,y) git_lstat(x,y) +#define fstat(x,y) git_fstat(x,y) #endif /* __MINGW32__ */ #endif From 01e3a15dd29ccbb1bca252c0da6b37a3f2dce958 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Wed, 5 Sep 2007 04:32:50 -0700 Subject: [PATCH 0222/3720] Fixed text file auto-detection: treat EOF character 032 at the end of file as printable Signed-off-by: Dmitry Kakurin --- convert.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/convert.c b/convert.c index 21908b1039..b288552280 100644 --- a/convert.c +++ b/convert.c @@ -58,6 +58,10 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat * else stats->printable++; } + + // If file ends with EOF then don't count this EOF as non-printable + if ( size >= 1 && buf[size-1] == '\032' ) + stats->nonprintable--; } /* From ade2a2dba35b2ee97e7a46bbc57a9bd1e3b24348 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Wed, 12 Sep 2007 11:46:39 -0400 Subject: [PATCH 0223/3720] git-gui: Correct error of not finding /share/git-gui/lib/tclIndex. Where the Makefile tests for Cygwin, it also needs to test for MINGW. Signed-off-by: Mike Pape --- git-gui/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-gui/Makefile b/git-gui/Makefile index 1bac6fed46..d8c5e65370 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -8,6 +8,7 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE -include GIT-VERSION-FILE uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') SCRIPT_SH = git-gui.sh GITGUI_BUILT_INS = git-citool @@ -86,7 +87,8 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)rm -f $@ $@+ && \ GITGUI_RELATIVE= && \ if test '$(exedir_SQ)' = '$(libdir_SQ)'; then \ - if test "$(uname_O)" = Cygwin; \ + if test "$(uname_O)" = Cygwin \ + -o "$(findstring MINGW,$(uname_S))" = MINGW; \ then GITGUI_RELATIVE= ; \ else GITGUI_RELATIVE=1; \ fi; \ From 6a561a80d5e02cd6364c577b8fc628bf8090ebff Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Wed, 12 Sep 2007 18:46:39 -0400 Subject: [PATCH 0224/3720] Revert "git-gui: Correct error of not finding /share/git-gui/lib/tclIndex." This reverts commit ade2a2dba35b2ee97e7a46bbc57a9bd1e3b24348. --- git-gui/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/git-gui/Makefile b/git-gui/Makefile index d8c5e65370..1bac6fed46 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -8,7 +8,6 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE -include GIT-VERSION-FILE uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') SCRIPT_SH = git-gui.sh GITGUI_BUILT_INS = git-citool @@ -87,8 +86,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)rm -f $@ $@+ && \ GITGUI_RELATIVE= && \ if test '$(exedir_SQ)' = '$(libdir_SQ)'; then \ - if test "$(uname_O)" = Cygwin \ - -o "$(findstring MINGW,$(uname_S))" = MINGW; \ + if test "$(uname_O)" = Cygwin; \ then GITGUI_RELATIVE= ; \ else GITGUI_RELATIVE=1; \ fi; \ From 3b9b1450636df0ceeb791e1f3837b5f711ae391e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Sep 2007 15:22:13 +0100 Subject: [PATCH 0225/3720] gitk: force focus to main window On msysGit, the focus is first on the (Tk) console. This console is then hidden, but keeps the focus. Work around that by forcing the focus onto the gitk window. This fixes issue 14. Signed-off-by: Johannes Schindelin --- gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk b/gitk index b3ca704bf7..89b6398963 100755 --- a/gitk +++ b/gitk @@ -8005,4 +8005,5 @@ if {[info exists permviews]} { addviewmenu $n } } +focus -force . getcommits From 416488563ef2f68c7ceaec016c4e96ab2fd45ba7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Sep 2007 15:54:53 +0100 Subject: [PATCH 0226/3720] Revert bd2f73a6(Support the tools scripted in perl.) This is not needed in msysGit, since we call Perl from inside MSys, and therefore paths are handled gracefully. Incidentally, it fixes issue 46 (msysGit fails to install in paths beginning with C). This reverts bd2f73a6ba6daf6158112874414d338c7b0e528d. Signed-off-by: Johannes Schindelin --- perl/Makefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/perl/Makefile b/perl/Makefile index f7dbfca616..5e079ad011 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -20,11 +20,7 @@ clean: $(RM) $(makfile).old ifdef NO_PERL_MAKEMAKER -# We exploit that /bin/sh transforms the DOS-Stype path in TEMP into -# the MSYS style pseudo-mount form. -# This colon-free from is needed because our perl scripts look at -# $(instdir_SQ) and split it at colons. -instdir_SQ = $(subst ','\'',$(shell cmd /x/d/c "set TEMP=$(prefix)/lib && sh -c 'echo \$$TEMP'")) +instdir_SQ = $(subst ','\'',$(prefix)/lib) $(makfile): ../GIT-CFLAGS Makefile echo all: > $@ echo ' :' >> $@ From 74c2a08ef9ec16ce4cb3daef0b65fad439448538 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Sep 2007 16:22:00 +0100 Subject: [PATCH 0227/3720] Do not complain about "no common commits" in an empty repo If the repo is empty, we know that already, thank you very much. So shut fetch-pack up about that case. Fixes issue 3, too. Signed-off-by: Johannes Schindelin --- fetch-pack.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fetch-pack.c b/fetch-pack.c index b6470932fb..ff79e56ac4 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -289,7 +289,8 @@ done: } flushes--; } - return retval; + /* it is no error to fetch into a completely empty repo */ + return count ? retval : 0; } static struct commit_list *complete; From b49fa05b92a7a369beca1de67fded5a6da500f9c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 20 Sep 2007 14:58:00 +0200 Subject: [PATCH 0228/3720] Handle fstat() of a socket descriptor. GetFileInformationByHandle() fails if it is passed a WinSock handle. Fortunately, the failure can be distinguished by the error code, and we can in this case pretend that the fstat() was actually successful. This is a valid thing to do: Calling fstat() on a descriptor makes only sense if either the caller needs information on the file (in which case we would not reach this error condition), or if it wants to distinguish a socket from a file (which implies that the caller will have to test st_mode, which happens to be the only field that we can fill in). Signed-off-by: Johannes Sixt --- compat/mingw.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 20eadd2334..166e2ad5f0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -123,8 +123,14 @@ int git_fstat(int fd, struct stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); BY_HANDLE_FILE_INFORMATION fdata; + char dummy[sizeof(void*)]; + int s = sizeof(void*); - if (fh != INVALID_HANDLE_VALUE && GetFileInformationByHandle(fh, &fdata)) { + if (fh == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + if (GetFileInformationByHandle(fh, &fdata)) { int fMode = S_IREAD; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) fMode |= S_IFDIR; @@ -145,7 +151,22 @@ int git_fstat(int fd, struct stat *buf) buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); return 0; } - errno = EBADF; + switch (GetLastError()) { + case ERROR_INVALID_FUNCTION: + /* check for socket */ + if (getsockopt((int)fh, SOL_SOCKET, SO_KEEPALIVE, dummy, &s) && + WSAGetLastError() == WSAENOTSOCK) + goto badf; + memset(buf, sizeof(*buf), 0); + buf->st_mode = S_IREAD|S_IWRITE; + buf->st_mode |= 0x140000; /* S_IFSOCK */ + return 0; + default: + case ERROR_INVALID_HANDLE: + badf: + errno = EBADF; + break; + } return -1; } From a64e23954fc617019354a929dcefaa6049c2f744 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 21 Sep 2007 21:31:51 +0200 Subject: [PATCH 0229/3720] git-commit: Implement racy-safe save_index() with ln instead of cp -p. git-commit must allocate a copy of the current index if only a subset of files is to be commited in save_index(). It uses 'cp -p' because the index may contain racily-clean entries, which will be detected only if the timestamp of the index remains unaltered. In general, it is safe to create a hardlink instead of copying the index because all writers use the lock_file infrastructure that writes a new file and moves it into the destination, breaking the hardlink. On Windows, in particular, 'cp -p' suffers from a mysterious inability to accurately preserve the timestamp under some circumstances. (This was detected by the test suite, where some racily clean files were not recognized.) 'ln' does create a hardlink on Windows on NTFS, and makes a copy with the correctly preserved timestamp on FAT. Signed-off-by: Johannes Sixt --- git-commit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-commit.sh b/git-commit.sh index 1d04f1ff31..427b48dd8b 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -29,7 +29,7 @@ THIS_INDEX="$GIT_DIR/index" NEXT_INDEX="$GIT_DIR/next-index$$" rm -f "$NEXT_INDEX" save_index () { - cp -p "$THIS_INDEX" "$NEXT_INDEX" + ln "$THIS_INDEX" "$NEXT_INDEX" } run_status () { From cd4ce16f0fa35828ce33cc2fa90b4ab6528a28ea Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 9 Sep 2007 21:00:47 +0200 Subject: [PATCH 0230/3720] Work around incompatible sort and find on windows. If the PATH lists the Windows system directories before the MSYS directories, Windows's own incompatible sort and find commands would be picked up. We implement these commands as functions and call the real tools by absolute path. Also add a dummy implementation of sync to avoid an error in git-repack. Signed-off-by: Johannes Sixt --- git-clone.sh | 10 ++++++++++ git-ls-remote.sh | 13 +++++++++++++ git-sh-setup.sh | 17 +++++++++++++++++ t/test-lib.sh | 13 +++++++++++++ 4 files changed, 53 insertions(+) diff --git a/git-clone.sh b/git-clone.sh index 7796201ada..e262f77136 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -13,6 +13,16 @@ die() { exit 1 } +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) find + find () { + /usr/bin/find "$@" + } + ;; +esac + usage() { die "Usage: $0 [--template=] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [--origin ] [--depth ] [-n] []" } diff --git a/git-ls-remote.sh b/git-ls-remote.sh index 4d37934f62..0d7508407b 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -12,6 +12,19 @@ die () { exit 1 } +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) sort and find + sort () { + /usr/bin/sort "$@" + } + find () { + /usr/bin/find "$@" + } + ;; +esac + exec= while case "$#" in 0) break;; esac do diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 185c5c6c95..74b2389d9a 100755 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -129,3 +129,20 @@ test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || { } : ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"} + +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) sort and find + sort () { + /usr/bin/sort "$@" + } + find () { + /usr/bin/find "$@" + } + # sync is missing + sync () { + : # no implementation + } + ;; +esac diff --git a/t/test-lib.sh b/t/test-lib.sh index a3f3d7c922..fed377fc1c 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -305,3 +305,16 @@ do test_done esac done + +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) sort and find + sort () { + /usr/bin/sort "$@" + } + find () { + /usr/bin/find "$@" + } + ;; +esac From b14adeb12da86dcea9dc683ab5970f176471ca36 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 9 Sep 2007 21:01:15 +0200 Subject: [PATCH 0231/3720] Undo /usr/bin/sort and /usr/bin/find workarounds. --- contrib/examples/git-tag.sh | 2 +- git-clone.sh | 6 +++--- git-ls-remote.sh | 4 ++-- git-mergetool.sh | 4 ++-- git-repack.sh | 4 ++-- t/t0000-basic.sh | 8 ++++---- t/t1200-tutorial.sh | 2 +- t/t2001-checkout-cache-clash.sh | 2 +- t/t3100-ls-tree-restrict.sh | 2 +- t/t3101-ls-tree-dirname.sh | 2 +- t/t4112-apply-renames.sh | 2 +- t/t5000-tar-tree.sh | 14 +++++++------- t/t5300-pack-object.sh | 6 +++--- t/t6003-rev-list-topo-order.sh | 2 +- t/t9107-git-svn-migrate.sh | 2 +- t/t9200-git-cvsexportcommit.sh | 4 ++-- t/t9300-fast-import.sh | 2 +- 17 files changed, 34 insertions(+), 34 deletions(-) diff --git a/contrib/examples/git-tag.sh b/contrib/examples/git-tag.sh index 181b9a7e97..5ee3f50a3c 100755 --- a/contrib/examples/git-tag.sh +++ b/contrib/examples/git-tag.sh @@ -53,7 +53,7 @@ do shift ;; esac - git rev-parse --symbolic --tags | /usr/bin/sort | + git rev-parse --symbolic --tags | sort | while read TAG do case "$TAG" in diff --git a/git-clone.sh b/git-clone.sh index e262f77136..6de44cde1f 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -285,7 +285,7 @@ yes) then # See if we can hardlink and drop "l" if not. sample_file=$(cd "$repo" && \ - /usr/bin/find objects -type f -print | sed -e 1q) + find objects -type f -print | sed -e 1q) # objects directory should not be empty because # we are cloning! test -f "$repo/$sample_file" || exit @@ -299,7 +299,7 @@ yes) fi fi && cd "$repo" && - /usr/bin/find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 + find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 fi git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 ;; @@ -416,7 +416,7 @@ then ( test -f "$GIT_DIR/$remote_top/master" && echo "master" cd "$GIT_DIR/$remote_top" && - /usr/bin/find . -type f -print | sed -e 's/^\.\///' + find . -type f -print | sed -e 's/^\.\///' ) | ( done=f while read name diff --git a/git-ls-remote.sh b/git-ls-remote.sh index 0d7508407b..984cef4dd0 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -92,7 +92,7 @@ rsync://* ) head=$(cat "$tmpdir/$head") || exit esac && echo "$head HEAD" - (cd $tmpdir && /usr/bin/find refs -type f) | + (cd $tmpdir && find refs -type f) | while read path do tr -d '\012' <"$tmpdir/$path" @@ -111,7 +111,7 @@ rsync://* ) fi ;; esac | -/usr/bin/sort -t ' ' -k 2 | +sort -t ' ' -k 2 | while read sha1 path do case "$sha1" in diff --git a/git-mergetool.sh b/git-mergetool.sh index e6bbb6bbd6..47a80553ad 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -364,13 +364,13 @@ case "$merge_tool" in esac if test $# -eq 0 ; then - files=`git ls-files -u | sed -e 's/^[^ ]* //' | /usr/bin/sort -u` + files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u` if test -z "$files" ; then echo "No files need merging" exit 0 fi echo Merging the files: $files - git ls-files -u | sed -e 's/^[^ ]* //' | /usr/bin/sort -u | while read i + git ls-files -u | sed -e 's/^[^ ]* //' | sort -u | while read i do printf "\n" merge_file "$i" < /dev/tty > /dev/tty diff --git a/git-repack.sh b/git-repack.sh index a8f44097e0..156c5e8f4a 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -48,7 +48,7 @@ case ",$all_into_one," in ;; ,t,) if [ -d "$PACKDIR" ]; then - for e in `cd "$PACKDIR" && /usr/bin/find . -type f -name '*.pack' \ + for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \ | sed -e 's/^\.\///' -e 's/\.pack$//'` do if [ -e "$PACKDIR/$e.keep" ]; then @@ -105,7 +105,7 @@ then # We know $existing are all redundant. if [ -n "$existing" ] then - sync 2> /dev/null + sync ( cd "$PACKDIR" && for e in $existing do diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index a213268cd6..0d8c4b18ba 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -50,14 +50,14 @@ test "$no_symlinks" && { # git init has been done in an empty repository. # make sure it is empty. -/usr/bin/find .git/objects -type f -print >should-be-empty +find .git/objects -type f -print >should-be-empty test_expect_success \ '.git/objects should be empty after git init in an empty repo.' \ 'cmp -s /dev/null should-be-empty' # also it should have 2 subdirectories; no fan-out anymore, pack, and info. # 3 is counting "objects" itself -/usr/bin/find .git/objects -type d -print >full-of-directories +find .git/objects -type d -print >full-of-directories test_expect_success \ '.git/objects should have 3 subdirectories.' \ 'test $(wc -l < full-of-directories) = 3' @@ -112,7 +112,7 @@ do done test_expect_success \ 'adding various types of objects with git update-index --add.' \ - '/usr/bin/find path* ! -type d -print | xargs git update-index --add' + 'find path* ! -type d -print | xargs git update-index --add' # Show them and see that matches what we expect. test_expect_success \ @@ -289,7 +289,7 @@ test_expect_success \ 'commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) && parent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | - /usr/bin/sort -u) && + sort -u) && test "z$commit0" = "z$parent" && numparent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh index 5cd9c48ddf..991d3c5e9c 100755 --- a/t/t1200-tutorial.sh +++ b/t/t1200-tutorial.sh @@ -156,6 +156,6 @@ test_expect_success 'git show-branch' 'cmp show-branch2.expect show-branch2.outp test_expect_success 'git repack' 'git repack' test_expect_success 'git prune-packed' 'git prune-packed' -test_expect_failure '-> only packed objects' '/usr/bin/find -type f .git/objects/[0-9a-f][0-9a-f]' +test_expect_failure '-> only packed objects' 'find -type f .git/objects/[0-9a-f][0-9a-f]' test_done diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh index 45b4bc47d6..c1e236e932 100755 --- a/t/t2001-checkout-cache-clash.sh +++ b/t/t2001-checkout-cache-clash.sh @@ -23,7 +23,7 @@ the symlink path1 and create directory path1 and file path1/file1. show_files() { # show filesystem files, just [-dl] for type and name - /usr/bin/find path? -ls | + find path? -ls | sed -e 's/^[0-9]* * [0-9]* * \([-bcdl]\)[^ ]* *[0-9]* *[^ ]* *[^ ]* *[0-9]* [A-Z][a-z][a-z] [0-9][0-9] [^ ]* /fs: \1 /' # what's in the cache, just mode and name git ls-files --stage | diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 4794fdd9eb..40c6f1d31f 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -38,7 +38,7 @@ test_expect_success \ echo Lo >path2/foo && ln -s ../path1 path2/bazbo && echo Mi >path2/baz/b && - /usr/bin/find path? \( -type f -o -type l \) -print | + find path? \( -type f -o -type l \) -print | xargs git update-index --add && tree=`git write-tree` && echo $tree' diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh index e6ebe51d1d..39fe2676dc 100755 --- a/t/t3101-ls-tree-dirname.sh +++ b/t/t3101-ls-tree-dirname.sh @@ -34,7 +34,7 @@ test_expect_success \ mkdir path3 && echo 111 >path3/1.txt && echo 222 >path3/2.txt && - /usr/bin/find *.txt path* \( -type f -o -type l \) -print | + find *.txt path* \( -type f -o -type l \) -print | xargs git update-index --add && tree=`git write-tree` && echo $tree' diff --git a/t/t4112-apply-renames.sh b/t/t4112-apply-renames.sh index fcdf99d65a..70a1859503 100755 --- a/t/t4112-apply-renames.sh +++ b/t/t4112-apply-renames.sh @@ -115,7 +115,7 @@ rename to include/arch/m32r/klibc/archsetjmp.h +#endif /* _KLIBC_ARCHSETJMP_H */ EOF -/usr/bin/find klibc -type f -print | xargs git update-index --add -- +find klibc -type f -print | xargs git update-index --add -- test_expect_success 'check rename/copy patch' 'git apply --check patch' diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index a76c0f632b..f17bc3ac0b 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -45,12 +45,12 @@ test_expect_success \ (p=long_path_to_a_file && cd a && for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && echo text >file_with_long_path) && - (cd a && /usr/bin/find .) | /usr/bin/sort >a.lst' + (cd a && find .) | sort >a.lst' test_expect_success \ 'add files to repository' \ - '/usr/bin/find a -type f | xargs git update-index --add && - /usr/bin/find a -type l | xargs git update-index --add && + 'find a -type f | xargs git update-index --add && + find a -type l | xargs git update-index --add && treeid=`git write-tree` && echo $treeid >treeid && git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \ @@ -87,7 +87,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd b/a && /usr/bin/find .) | /usr/bin/sort >b.lst && + '(cd b/a && find .) | sort >b.lst && diff a.lst b.lst' test_expect_success \ @@ -104,7 +104,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd c/prefix/a && /usr/bin/find .) | /usr/bin/sort >c.lst && + '(cd c/prefix/a && find .) | sort >c.lst && diff a.lst c.lst' test_expect_success \ @@ -128,7 +128,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd d/a && /usr/bin/find .) | /usr/bin/sort >d.lst && + '(cd d/a && find .) | sort >d.lst && diff a.lst d.lst' test_expect_success \ @@ -145,7 +145,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd e/prefix/a && /usr/bin/find .) | /usr/bin/sort >e.lst && + '(cd e/prefix/a && find .) | sort >e.lst && diff a.lst e.lst' test_expect_success \ diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index a232f41edf..9a81d84106 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -75,7 +75,7 @@ cd "$TRASH/.git2" test_expect_success \ 'check unpack without delta' \ - '(cd ../.git && /usr/bin/find objects -type f -print) | + '(cd ../.git && find objects -type f -print) | while read path do cmp $path ../.git/$path || { @@ -105,7 +105,7 @@ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ 'check unpack with REF_DELTA' \ - '(cd ../.git && /usr/bin/find objects -type f -print) | + '(cd ../.git && find objects -type f -print) | while read path do cmp $path ../.git/$path || { @@ -135,7 +135,7 @@ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ 'check unpack with OFS_DELTA' \ - '(cd ../.git && /usr/bin/find objects -type f -print) | + '(cd ../.git && find objects -type f -print) | while read path do cmp $path ../.git/$path || { diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh index b507bd8078..5daa0be8cc 100755 --- a/t/t6003-rev-list-topo-order.sh +++ b/t/t6003-rev-list-topo-order.sh @@ -10,7 +10,7 @@ test_description='Tests git rev-list --topo-order functionality' list_duplicates() { - "$@" | /usr/bin/sort | uniq -d + "$@" | sort | uniq -d } date >path0 diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index e4b030b93e..67fdf7023f 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -65,7 +65,7 @@ test_expect_success 'multi-fetch works on partial urls + paths' " for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do git rev-parse --verify refs/remotes/\$i^0 >> refs.out || exit 1; done && - test -z \"\`/usr/bin/sort < refs.out | uniq -d\`\" && + test -z \"\`sort < refs.out | uniq -d\`\" && for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do for j in trunk a b tags/0.1 tags/0.2 tags/0.3; do if test \$j != \$i; then continue; fi diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 9b271f2729..910c584f24 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -30,7 +30,7 @@ exit 1 check_entries () { # $1 == directory, $2 == expected - grep '^/' "$1/CVS/Entries" | /usr/bin/sort | cut -d/ -f2,3,5 >actual + grep '^/' "$1/CVS/Entries" | sort | cut -d/ -f2,3,5 >actual if test -z "$2" then >expected @@ -186,7 +186,7 @@ test_expect_success \ if p="Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" && mkdir -p "tst/$p" && date >"tst/$p/day" && - found=$(/usr/bin/find tst -type f -print) && + found=$(find tst -type f -print) && test "z$found" = "ztst/$p/day" && rm -fr tst then diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index a64f78f5a0..0595041af5 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -880,7 +880,7 @@ INPUT_END test_expect_success \ 'O: blank lines not necessary after other commands' \ 'git-fast-import actual && git diff expect actual' From 3b06d6b12bc0576a908964625399cd3749fa0d04 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 22 Sep 2007 20:08:21 +0200 Subject: [PATCH 0232/3720] t5302-pack-index: Skip tests of 64-bit offsets if necessary. There are platforms where off_t is not 64 bits wide. In this case many tests are doomed to fail. Let's skip them. Signed-off-by: Johannes Sixt --- t/t5302-pack-index.sh | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 4f58c4c3f9..d93abc4c75 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -61,17 +61,33 @@ test_expect_success \ test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ - 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 &1) || + ! echo "$msg" | grep "pack too large .* off_t" +then + have_64bits=t +else + say "skipping tests concerning 64-bit offsets" +fi + +test "$have_64bits" && +test_expect_success \ + 'index v2: verify a pack with some 64-bit offsets' \ + 'git verify-pack -v "test-3-${pack3}.pack"' + +test "$have_64bits" && test_expect_failure \ '64-bit offsets: should be different from previous index v2 results' \ 'cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"' +test "$have_64bits" && test_expect_success \ 'index v2: force some 64-bit offsets with index-pack' \ 'git-index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"' +test "$have_64bits" && test_expect_success \ '64-bit offsets: index-pack result should match pack-objects one' \ 'cmp "test-3-${pack3}.idx" "3.idx"' @@ -113,6 +129,7 @@ test_expect_failure \ '[index v1] 6) newly created pack is BAD !' \ 'git verify-pack -v "test-4-${pack1}.pack"' +test "$have_64bits" && test_expect_success \ '[index v2] 1) stream pack to repository' \ 'rm -f .git/objects/pack/* && @@ -122,6 +139,7 @@ test_expect_success \ cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" && cmp "test-3-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx"' +test "$have_64bits" && test_expect_success \ '[index v2] 2) create a stealth corruption in a delta base reference' \ '# this test assumes a delta smaller than 16 bytes at the end of the pack @@ -134,14 +152,17 @@ test_expect_success \ bs=1 count=20 conv=notrunc && git cat-file blob "$delta_sha1" > blob_4 )' +test "$have_64bits" && test_expect_failure \ '[index v2] 3) corrupted delta happily returned wrong data' \ 'cmp blob_3 blob_4' +test "$have_64bits" && test_expect_failure \ '[index v2] 4) confirm that the pack is actually corrupted' \ 'git fsck --full $commit' +test "$have_64bits" && test_expect_failure \ '[index v2] 5) pack-objects refuses to reuse corrupted data' \ 'git pack-objects test-5 Date: Mon, 3 Sep 2007 18:15:39 +0200 Subject: [PATCH 0233/3720] Avoid /dev/null on the command line. The shell turns it into 'nul' (which we can't understand as an existing file). --- t/t4116-apply-reverse.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 9ae2b3a8ef..359f347b2c 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -42,7 +42,8 @@ test_expect_success 'apply in reverse' ' git reset --hard second && git apply --reverse --binary --index patch && git diff >diff && - git diff /dev/null diff + : > empty && + git diff empty diff ' From f3370bd1919751a28c206b19a743783a7c78c6da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 Sep 2007 02:00:46 +0100 Subject: [PATCH 0234/3720] t7004: work around weird quoting issue with MSys It seems to be impossible to pass the _string_ '*a*' if there is _any_ file in the current directory whose name contains the letter 'a'. So remove all such files for the test that needs to pass that string. Signed-off-by: Johannes Schindelin --- t/t7004-tag.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 606d4f2a2c..a1a69c0380 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -185,8 +185,9 @@ cba EOF test_expect_success \ 'listing tags with substring as pattern must print those matching' ' - git-tag -l "*a*" > actual && - git diff expect actual + rm *a* && + git-tag -l "*a*" > current && + git diff expect current ' cat >expect < Date: Fri, 7 Sep 2007 13:05:00 +0200 Subject: [PATCH 0235/3720] MinGW: Add a custom implementation for utime(). There seems to be a problem with Microsoft's utime() implementation. With this implementation we ensure that the files times written are UTC. Signed-off-by: Johannes Sixt --- test-chmtime.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test-chmtime.c b/test-chmtime.c index 90da448ebe..b6dc548a2a 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -3,6 +3,38 @@ static const char usage_str[] = "(+|=|=+|=-|-) ..."; +#ifdef __MINGW32__ +static inline void time_t_to_filetime(time_t t, FILETIME *ft) +{ + long long winTime = t * 10000000LL + 116444736000000000LL; + ft->dwLowDateTime = winTime; + ft->dwHighDateTime = winTime >> 32; +} + +int git_utime (const char *file_name, const struct utimbuf *times) +{ + FILETIME mft, aft; + int fh, rc; + + /* must have write permission */ + if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) + return -1; + + time_t_to_filetime(times->modtime, &mft); + time_t_to_filetime(times->actime, &aft); + if (!SetFileTime(_get_osfhandle(fh), NULL, &aft, &mft)) { + errno = EINVAL; + rc = -1; + } else + rc = 0; + close(fh); + return rc; +} + +int git_utime(const char *file_name, const struct utimbuf *times); +#define utime git_utime +#endif /* __MINGW32__ */ + int main(int argc, const char *argv[]) { int i; From 4ff71c309b1454f6ec7381306449017fd686944b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 23 Sep 2007 14:39:21 +0100 Subject: [PATCH 0236/3720] Quick 'n dirty compile fix for missing msgfmt I only wanted to see the latest and greatest in terms of running git-gui in a directory that is not a git directory. We'll fix that missing msgfmt issue later. Signed-off-by: Johannes Schindelin --- git-gui/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/Makefile b/git-gui/Makefile index 6236dd6ad3..065a090c91 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -141,7 +141,7 @@ $(PO_TEMPLATE): $(SCRIPT_SH) $(ALL_LIBFILES) update-po:: $(PO_TEMPLATE) $(foreach p, $(ALL_POFILES), echo Updating $p ; msgmerge -U $p $(PO_TEMPLATE) ; ) $(ALL_MSGFILES): %.msg : %.po - $(QUIET_MSGFMT0)$(MSGFMT) --statistics --tcl $< -l $(basename $(notdir $<)) -d $(dir $@) $(QUIET_MSGFMT1) + $(QUIET_MSGFMT0)touch $@ $(QUIET_MSGFMT1) lib/tclIndex: $(ALL_LIBFILES) $(QUIET_INDEX)if echo \ From 3be4fa22e9e50839cfb3fb50970b8a247774c592 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 23 Sep 2007 14:42:46 +0100 Subject: [PATCH 0237/3720] git-gui: actually show the choose repository dialog For some reason, "." was withdrawn, I think. Therefore we have to deiconify it, so the user sees something. Signed-off-by: Johannes Schindelin --- git-gui/lib/choose_repository.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 1bec8bd0a8..5f2d12fd07 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -123,6 +123,7 @@ constructor pick {} { grab $top focus $top " + wm deiconify $top tkwait variable @done if {$top eq {.}} { From 071ba61874592b990aded3f61bb444354985d765 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 24 Sep 2007 13:46:42 +0100 Subject: [PATCH 0238/3720] Revert "Quick 'n dirty compile fix for missing msgfmt" This reverts commit 4ff71c309b1454f6ec7381306449017fd686944b. --- git-gui/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/Makefile b/git-gui/Makefile index 065a090c91..6236dd6ad3 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -141,7 +141,7 @@ $(PO_TEMPLATE): $(SCRIPT_SH) $(ALL_LIBFILES) update-po:: $(PO_TEMPLATE) $(foreach p, $(ALL_POFILES), echo Updating $p ; msgmerge -U $p $(PO_TEMPLATE) ; ) $(ALL_MSGFILES): %.msg : %.po - $(QUIET_MSGFMT0)touch $@ $(QUIET_MSGFMT1) + $(QUIET_MSGFMT0)$(MSGFMT) --statistics --tcl $< -l $(basename $(notdir $<)) -d $(dir $@) $(QUIET_MSGFMT1) lib/tclIndex: $(ALL_LIBFILES) $(QUIET_INDEX)if echo \ From f98e862b3105ba14891c71bbe6dfb9ea677f84cc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 24 Sep 2007 13:51:57 +0100 Subject: [PATCH 0239/3720] git-gui: add a simple msgfmt replacement The program "msgfmt" was our only dependency on gettext. Since it is more than just a hassle to compile gettext on MinGW, here is a (very simple) drop-in replacement, which Works For Us. Signed-off-by: Johannes Schindelin --- git-gui/Makefile | 2 +- git-gui/po/po2msg.sh | 103 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 git-gui/po/po2msg.sh diff --git a/git-gui/Makefile b/git-gui/Makefile index 6236dd6ad3..b9affa4d7c 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -129,7 +129,7 @@ $(GITGUI_BUILT_INS): git-gui $(QUIET_BUILT_IN)rm -f $@ && ln git-gui $@ XGETTEXT ?= xgettext -MSGFMT ?= msgfmt +MSGFMT ?= po/po2msg.sh msgsdir = $(gg_libdir)/msgs msgsdir_SQ = $(subst ','\'',$(msgsdir)) PO_TEMPLATE = po/git-gui.pot diff --git a/git-gui/po/po2msg.sh b/git-gui/po/po2msg.sh new file mode 100644 index 0000000000..da0765dd80 --- /dev/null +++ b/git-gui/po/po2msg.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec tclsh "$0" -- "$@" + +# This is a really stupid program, which serves as an alternative to +# msgfmt. It _only_ translates to Tcl mode, does _not_ validate the +# input, and does _not_ output any statistics. + +proc u2a {s} { + set res "" + foreach i [split $s ""] { + scan $i %c c + if {$c<128} { + # escape '[', '\' and ']' + if {$c == 0x5b || $c == 0x5d} { + append res "\\" + } + append res $i + } else { + append res \\u[format %04.4x $c] + } + } + return $res +} + +set output_directory "." +set lang "dummy" +set files [list] + +# parse options +for {set i 1} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + if {$arg == "--statistics" || $arg == "--tcl"} { + continue + } + if {$arg == "-l"} { + incr i + set lang [lindex $argv $i] + continue + } + if {$arg == "-d"} { + incr i + set tmp [lindex $argv $i] + regsub "\[^/\]$" $tmp "&/" output_directory + continue + } + lappend files $arg +} + +proc flush_msg {} { + global msgid msgstr mode lang out + + if {![info exists msgid] || $mode == ""} { + return + } + set mode "" + + if {$msgid == ""} { + set prefix "set ::msgcat::header" + } else { + set prefix "::msgcat::mcset $lang \"[u2a $msgid]\"" + } + + puts $out "$prefix \"[u2a $msgstr]\"" +} + +foreach file $files { + regsub "^.*/\(\[^/\]*\)\.po$" $file "$output_directory\\1.msg" outfile + set in [open $file "r"] + fconfigure $in -encoding utf-8 + set out [open $outfile "w"] + + set mode "" + while {[gets $in line] >= 0} { + if {[regexp "^#" $line]} { + flush_msg + continue + } elseif {[regexp "^msgid \"(.*)\"$" $line dummy match]} { + flush_msg + set msgid $match + set mode "msgid" + } elseif {[regexp "^msgstr \"(.*)\"$" $line dummy match]} { + set msgstr $match + set mode "msgstr" + } elseif {$line == ""} { + flush_msg + } elseif {[regexp "^\"(.*)\"$" $line dummy match]} { + if {$mode == "msgid"} { + append msgid $match + } elseif {$mode == "msgstr"} { + append msgstr $match + } else { + puts stderr "I do not know what to do: $match" + } + } else { + puts stderr "Cannot handle $line" + } + } + flush_msg + close $in + close $out +} + From b0eef9af247c5e06451b82e2ada82351158f5f5f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 24 Sep 2007 21:13:50 +0200 Subject: [PATCH 0240/3720] Do not return EFAULT for ERROR_INVALID_NAME. A file name that contains a colon will be rejected by GeFileInformation() with ERROR_INVALID_NAME. This must be treated as ENOENT. Such a file name ends up in do_lstat() when the rev:path notation is used (eg. in 'git show'). --- compat/mingw.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 166e2ad5f0..af522f1666 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -76,9 +76,6 @@ static int do_lstat(const char *file_name, struct stat *buf) case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; - case ERROR_INVALID_NAME: - errno = EFAULT; - break; default: errno = ENOENT; break; From 56dc8fc47aa94fb74f824d8994f0b5340cd0228a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 25 Sep 2007 12:32:27 +0200 Subject: [PATCH 0241/3720] Fix fstat() implementation for pipes and sockets again. It turns out that GetFileInformationByHandle() succeeds even for pipes and sockets. Hence, we fall back to Windows's own fstat() implementation for everything except files. This also takes care of any error codes (again, except for files - but we don't expect any errors here). --- compat/mingw.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index af522f1666..8bb0dba16c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -116,17 +116,20 @@ int git_lstat(const char *file_name, struct stat *buf) return do_lstat(alt_name, buf); } +#undef fstat int git_fstat(int fd, struct stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); BY_HANDLE_FILE_INFORMATION fdata; - char dummy[sizeof(void*)]; - int s = sizeof(void*); if (fh == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } + /* direct non-file handles to MS's fstat() */ + if (GetFileType(fh) != FILE_TYPE_DISK) + return fstat(fd, buf); + if (GetFileInformationByHandle(fh, &fdata)) { int fMode = S_IREAD; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) @@ -148,22 +151,7 @@ int git_fstat(int fd, struct stat *buf) buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); return 0; } - switch (GetLastError()) { - case ERROR_INVALID_FUNCTION: - /* check for socket */ - if (getsockopt((int)fh, SOL_SOCKET, SO_KEEPALIVE, dummy, &s) && - WSAGetLastError() == WSAENOTSOCK) - goto badf; - memset(buf, sizeof(*buf), 0); - buf->st_mode = S_IREAD|S_IWRITE; - buf->st_mode |= 0x140000; /* S_IFSOCK */ - return 0; - default: - case ERROR_INVALID_HANDLE: - badf: - errno = EBADF; - break; - } + errno = EBADF; return -1; } From 803d403a7393ab267b4da1e0d57d7ee8782f2128 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 29 Sep 2007 17:40:06 +0200 Subject: [PATCH 0242/3720] help (msysgit): print message telling the user that browser is launched git doesn't wait until the browser is launched but returns immediatly. A user may feel more comfortable if he knows that eventually the help will appear. Signed-off-by: Steffen Prohaska --- help.c | 1 + 1 file changed, 1 insertion(+) diff --git a/help.c b/help.c index e7da8ae430..98d00cc4d9 100644 --- a/help.c +++ b/help.c @@ -193,6 +193,7 @@ static void show_man_page(const char *git_cmd) strcpy (htmlpath + prefix_len, page); strcpy (htmlpath + prefix_len + page_len, suffix); htmlpath[htmlpath_len] = 0; + printf("Launching default browser to display html help...\n"); /* We need sh here to run shell script /bin/start. */ execlp("sh", "start", "/bin/start", htmlpath, NULL ); } From 65230e232c91527c16724a665e5d5f2ea670f9b6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 1 Oct 2007 22:56:45 +0200 Subject: [PATCH 0243/3720] help (msysgit): fix locating html help for paths with spaces Derive the git installation dir from the executable path and directly use the Win32 API to open the HTML file. This avoids the mingw layer and command line escaping problems, which caused the previous implementation to fail if spaces were contained in the path to git. Signed-off-by: Steffen Prohaska --- help.c | 60 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/help.c b/help.c index 98d00cc4d9..a5ada18c76 100644 --- a/help.c +++ b/help.c @@ -165,6 +165,32 @@ static void list_common_cmds_help(void) puts("(use 'git help -a' to get a list of all installed git commands)"); } +#ifdef __MINGW32__ +char* get_install_dir() +{ + static char* pgm = 0; + if (pgm) { + return pgm; + } else { + char* p; + int pgm_len = strlen(_pgmptr); + pgm = xmalloc(pgm_len + 1); + strcpy(pgm, _pgmptr); + p = strrchr(pgm, '\\'); /* \bin\ <- p */ + if (p) { + *p = '\0'; + p = strrchr(pgm, '\\'); /* \ <- p */ + if (p) { + *p = '\0'; + return pgm; + } + } + } + fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); + exit(1); +} +#endif + static void show_man_page(const char *git_cmd) { const char *page; @@ -181,22 +207,24 @@ static void show_man_page(const char *git_cmd) } #ifdef __MINGW32__ - { - char* prefix = "/doc/git/html/"; - int prefix_len = strlen (prefix); - char* suffix = ".html"; - int suffix_len = strlen (suffix); - int page_len = strlen (page); - int htmlpath_len = prefix_len + page_len + suffix_len; - char* htmlpath = xmalloc (htmlpath_len + 1); - strcpy (htmlpath, prefix); - strcpy (htmlpath + prefix_len, page); - strcpy (htmlpath + prefix_len + page_len, suffix); - htmlpath[htmlpath_len] = 0; - printf("Launching default browser to display html help...\n"); - /* We need sh here to run shell script /bin/start. */ - execlp("sh", "start", "/bin/start", htmlpath, NULL ); - } + { + char* install_dir = get_install_dir(); + int install_dir_len = strlen(install_dir); + char* html_dir = "\\doc\\git\\html\\"; + int html_dir_len = strlen(html_dir); + char* suffix = ".html"; + int suffix_len = strlen(suffix); + int page_len = strlen(page); + int htmlpath_len = install_dir_len + html_dir_len + page_len + suffix_len; + char* htmlpath = xmalloc(htmlpath_len + 1); + strcpy (htmlpath, install_dir); + strcpy (htmlpath + install_dir_len, html_dir); + strcpy (htmlpath + install_dir_len + html_dir_len, page); + strcpy (htmlpath + install_dir_len + html_dir_len + page_len, suffix); + htmlpath[htmlpath_len] = 0; + printf("Launching default browser to display html help...\n"); + ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); + } #else execlp("man", "man", page, NULL); #endif From fc98ff08304caa36420028f1b5cfaa6cfdccf3d6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 2 Oct 2007 15:25:15 +0200 Subject: [PATCH 0244/3720] help (msysgit): beautify message telling user that HTML will be display Signed-off-by: Steffen Prohaska --- help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help.c b/help.c index a5ada18c76..f4a0208ff3 100644 --- a/help.c +++ b/help.c @@ -222,7 +222,7 @@ static void show_man_page(const char *git_cmd) strcpy (htmlpath + install_dir_len + html_dir_len, page); strcpy (htmlpath + install_dir_len + html_dir_len + page_len, suffix); htmlpath[htmlpath_len] = 0; - printf("Launching default browser to display html help...\n"); + printf("Launching default browser to display HTML help ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); } #else From ded3d5f4962928feec8060cab0bbd96e7443a3dd Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 4 Oct 2007 07:45:31 +0200 Subject: [PATCH 0245/3720] help (msysgit): add comment about assumption on _pgmptr --- help.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/help.c b/help.c index f4a0208ff3..1c0946c649 100644 --- a/help.c +++ b/help.c @@ -186,6 +186,8 @@ char* get_install_dir() } } } + /* Note, according to the msdn documentation we have a full path + if started through the shell and this error should never happen. */ fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); exit(1); } From 524344cdf5b16871f027bf029eeee7774d337c37 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 10 Oct 2007 09:00:19 +0200 Subject: [PATCH 0246/3720] Fix invocation of external git commands with arguments with spaces. If an external git command (not a shell script) was invoked with arguments that contain spaces, these arguments would be split into separate arguments. They must be quoted. This also affected installations where $prefix contained a space, as in "C:\Program Files\GIT". Both errors can be triggered by invoking git hash-object "a b" where "a b" is an existing file. --- compat/mingw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8bb0dba16c..2554f19765 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -405,7 +405,12 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { - int ret = spawnve(_P_WAIT, cmd, argv, env); + const char **qargv; + int n; + for (n = 0; argv[n];) n++; + qargv = xmalloc((n+1)*sizeof(char*)); + quote_argv(qargv, argv); + int ret = spawnve(_P_WAIT, cmd, qargv, env); if (ret != -1) exit(ret); } From 73b51e93d2927af2fa9f332f31c25ca2319bd0dd Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 18:40:36 +0200 Subject: [PATCH 0247/3720] Work around a Windows oddity when a pipe with no reader is written to. The first WriteFile() returns ERROR_BROKEN_PIPE, subsequent WriteFile()s return ERROR_NO_DATA, which is not translated to EPIPE, but EINVAL. Hmpf! --- write_or_die.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/write_or_die.c b/write_or_die.c index e125e11d3b..40b046acb0 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -34,7 +34,16 @@ void maybe_flush_or_die(FILE *f, const char *desc) return; } if (fflush(f)) { +#ifndef __MINGW32__ if (errno == EPIPE) +#else + /* + * On Windows, EPIPE is returned only by the first write() + * after the reading end has closed its handle; subsequent + * write()s return EINVAL. + */ + if (errno == EPIPE || errno == EINVAL) +#endif exit(0); die("write failure on %s: %s", desc, strerror(errno)); } From fbb7b31c456f4c950a744a93d8521e8ef0145038 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 10 Oct 2007 09:00:12 +0200 Subject: [PATCH 0248/3720] Fix invocation of external git commands with arguments with spaces. If an external git command (not a shell script) was invoked with arguments that contain spaces, these arguments would be split into separate arguments. They must be quoted. This also affected installations where $prefix contained a space, as in "C:\Program Files\GIT". Both errors can be triggered by invoking git hash-object "a b" where "a b" is an existing file. --- compat/mingw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6632192690..f2b0ad3428 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -298,7 +298,12 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { - int ret = spawnve(_P_WAIT, cmd, argv, env); + const char **qargv; + int n; + for (n = 0; argv[n];) n++; + qargv = xmalloc((n+1)*sizeof(char*)); + quote_argv(qargv, argv); + int ret = spawnve(_P_WAIT, cmd, qargv, env); if (ret != -1) exit(ret); } From b171dc19ec37692d0791bc0d84866399fc42da94 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 16 Oct 2007 22:52:12 +0200 Subject: [PATCH 0249/3720] Implement a cpio emulation inside git-clone.sh for Windows. We use 'xargs cp' to emulate 'cpio -pumd'. cpio is fed from the output of 'find --depth' without filtering out directories. We don't need to copy directories except the empty ones, so we need to filter out non-empty directories. Then we can use 'cp -r' and it will not actually recurse anything. Signed-off-by: Johannes Sixt --- git-clone.sh | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/git-clone.sh b/git-clone.sh index cb6f2daef0..0154a4a381 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -20,6 +20,33 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + # need an emulation of cpio + cpio() { + case "$1" in + -pumd) cp_arg=-pr;; + -pumdl) cp_arg=-lr;; + *) die "cpio $1 unexpected";; + esac + # copy only files and empty directories + prev= + while read f; do + if test -d "$f"; then + # here we assume that directories are listed after + # its files (aka 'find -depth'), hence, a directory + # that is not empty will be a leading sub-string + # of the preceding entry + case "$prev" in + "$f"/* ) ;; + *) echo "$f";; + esac + else + echo "$f" + fi + prev="$f" + done | + xargs --no-run-if-empty \ + cp $cp_arg --target-directory="$2" --parents + } ;; esac From 8b9de093190e6b1d6066efaf4afd9dc988096987 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 17 Oct 2007 14:35:10 +0200 Subject: [PATCH 0250/3720] Implement a cpio emulation in git-merge.sh for Windows. GNU tar is used as the archiver. It doesn't matter that the archive has a different format because it is only a temporary stash that is consumed by the emulation itself. Signed-off-by: Johannes Sixt --- git-merge.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/git-merge.sh b/git-merge.sh index cde09d4d60..0f15884b54 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -26,6 +26,24 @@ use_strategies= allow_fast_forward=t allow_trivial_merge=t +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # there's no cpio; emulate with tar + cpio () { + case "$*" in + "-0 -o") + tar --create --file=- --null --files-from=- + ;; + "-iuv") + tar xvf - + ;; + *) die "internal error: unexpected cpio $*";; + esac + } + ;; +esac + dropsave() { rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \ "$GIT_DIR/MERGE_SAVE" || exit 1 From 4a7c98dbaf129f2546f8b8780650b4041c336228 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 17 Oct 2007 14:38:39 +0200 Subject: [PATCH 0251/3720] Remove the cpio emulator script. The users of cpio have their own emulation by now. --- .gitignore | 1 - Makefile | 1 - cpio.sh | 60 ------------------------------------------------------ 3 files changed, 62 deletions(-) delete mode 100644 cpio.sh diff --git a/.gitignore b/.gitignore index 2cb4002ba8..63c918c667 100644 --- a/.gitignore +++ b/.gitignore @@ -172,4 +172,3 @@ config.status config.mak.autogen config.mak.append configure -cpio diff --git a/Makefile b/Makefile index ea00d44337..5171a69425 100644 --- a/Makefile +++ b/Makefile @@ -500,7 +500,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig - SCRIPT_SH += cpio.sh endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease diff --git a/cpio.sh b/cpio.sh deleted file mode 100644 index df5f64c14c..0000000000 --- a/cpio.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh -# -# Emulates some cpio behavior using GNU tar - -die() { - echo >&2 "$@" - exit 1 -} - -null= - -while test $# -gt 0; do - case "$1" in - -0) null=--null;; - -o) mode=o;; - -iuv) ;; - -pumd|-pumdl) - mode=p - dir="$2" - shift - ;; - *) die "cpio emulation supports only -0, -o, -iuv, -pumdl";; - esac - shift -done - -prev= - -filterdirs() { - while read f; do - if test -d "$f"; then - # list only empty directories - # here we assume that directories are listed after - # its files (aka 'find -depth'), hence, a directory - # that is not empty will be a leading sub-string - # of the preceding entry - case "$prev" in - "$f"/* ) ;; - *) echo "$f";; - esac - else - echo "$f" - fi - prev="$f" - done -} - -case $mode in -o) - tar --create --file=- $null --files-from=- - ;; -p) - test -z "$null" || die "cpio: cannot use -0 in pass-through mode" - filterdirs | - tar --create --file=- --files-from=- | - tar --extract --directory="$dir" --file=- - ;; -*) - tar xvf - -esac From 2f346edb63d87f5c196f6254ce05e411548da04f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 18 Oct 2007 21:27:46 +0200 Subject: [PATCH 0252/3720] attr: fix segfault in gitattributes parsing code git may segfault if gitattributes contains an invalid entry. A test is added to t0020 that triggers the segfault. The parsing code is fixed to avoid the crash. Signed-off-by: Steffen Prohaska --- attr.c | 5 ++++- t/t0020-crlf.sh | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/attr.c b/attr.c index 129399310a..6e82507be7 100644 --- a/attr.c +++ b/attr.c @@ -214,8 +214,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, num_attr = 0; cp = name + namelen; cp = cp + strspn(cp, blank); - while (*cp) + while (*cp) { cp = parse_attr(src, lineno, cp, &num_attr, res); + if (!cp) + return NULL; + } if (pass) break; res = xcalloc(1, diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh index 0807d9f01a..62bc4bb077 100755 --- a/t/t0020-crlf.sh +++ b/t/t0020-crlf.sh @@ -371,4 +371,11 @@ test_expect_success 'in-tree .gitattributes (4)' ' } ' +test_expect_success 'invalid .gitattributes (must not crash)' ' + + echo "three +crlf" >>.gitattributes && + git diff + +' + test_done From 2671981e99996146c5624fb6005265805d29bfce Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 19 Oct 2007 22:51:50 +0200 Subject: [PATCH 0253/3720] Windows does not have memmem(). Signed-off-by: Johannes Sixt --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 9fa72a8a07..a048c061fa 100644 --- a/Makefile +++ b/Makefile @@ -501,6 +501,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_UNSETENV=YesPlease NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease + NO_MEMMEM = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease From 5fd41ffacdef5454acbe51f5e23a97eb5158226d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Oct 2007 14:01:27 +0200 Subject: [PATCH 0254/3720] Implement a work-around for a mis-behaved vsnprintf on Windows. On Windows, vsnprintf returns -1 if the buffer is too small instead of the number of characters needed. This wrapper computes the needed buffer size by trying various sizes with exponential growth. A large growth factor is used so as only few trials are required if a really large result needs to be stored. Signed-off-by: Johannes Sixt --- compat/mingw.c | 26 ++++++++++++++++++++++++++ git-compat-util.h | 4 ++++ 2 files changed, 30 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 2554f19765..43eda9e174 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -459,3 +459,29 @@ int mingw_rename(const char *pold, const char *pnew) errno = EACCES; return -1; } + +#undef vsnprintf +/* this is out of line because it uses alloca() behind the scenes, + * which must not be called in a loop (alloca() reclaims the allocations + * only at function exit) + */ +static int try_vsnprintf(size_t size, const char *fmt, va_list args) +{ + char buf[size]; /* gcc-ism */ + return vsnprintf(buf, size, fmt, args); +} + +int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int len = vsnprintf(buf, size, fmt, args); + if (len >= 0) + return len; + /* ouch, buffer too small; need to compute the size */ + if (size < 250) + size = 250; + do { + size *= 4; + len = try_vsnprintf(size, fmt, args); + } while (len < 0); + return len; +} diff --git a/git-compat-util.h b/git-compat-util.h index f52ced3763..e4f643d70b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -503,6 +503,10 @@ int git_fstat(int fd, struct stat *buf); #define lstat(x,y) git_lstat(x,y) #define stat(x,y) git_lstat(x,y) #define fstat(x,y) git_fstat(x,y) + +int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); +#define vsnprintf mingw_vsnprintf + #endif /* __MINGW32__ */ #endif From e88aa8cbe816526bb0a7d37eaf2f5eb40ff36ae1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Oct 2007 16:34:09 +0200 Subject: [PATCH 0255/3720] Fix off-by-one error in the vsnprintf wrapper. Windows's vsnprintf() receives the number of characters to write, which does not include the trailing NUL byte. But our vsnprintf() users pass the available space, including the trailing NUL. --- compat/mingw.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 43eda9e174..22b5e1072e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -461,21 +461,29 @@ int mingw_rename(const char *pold, const char *pnew) } #undef vsnprintf -/* this is out of line because it uses alloca() behind the scenes, +/* Note that the size parameter specifies the available space, i.e. + * includes the trailing NUL byte; but Windows's vsnprintf expects the + * number of characters to write without the trailing NUL. + */ + +/* This is out of line because it uses alloca() behind the scenes, * which must not be called in a loop (alloca() reclaims the allocations - * only at function exit) + * only at function exit). */ static int try_vsnprintf(size_t size, const char *fmt, va_list args) { char buf[size]; /* gcc-ism */ - return vsnprintf(buf, size, fmt, args); + return vsnprintf(buf, size-1, fmt, args); } int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { - int len = vsnprintf(buf, size, fmt, args); - if (len >= 0) - return len; + int len; + if (size > 0) { + len = vsnprintf(buf, size-1, fmt, args); + if (len >= 0) + return len; + } /* ouch, buffer too small; need to compute the size */ if (size < 250) size = 250; From 4e8904080d62be07a139436aa44044e05e380a2c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 24 Oct 2007 22:47:14 +0200 Subject: [PATCH 0256/3720] Makefile: avoid absolute Windows path in built executables MINGW converts an intial '/' in paths to the full Windows path of MINGW's rootdir. Therefore, the result of the build cannot be installed in another directory. This is fixed by replacing the initial '/' by its octal escape sequence that represents '/' in C strings. This sequence avoids the path conversion. Note, the Makefile contains the full path and can not be used any longer to build git with a different prefix. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 77a011f4a9..8f2f0300f2 100644 --- a/Makefile +++ b/Makefile @@ -735,12 +735,12 @@ endif # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) -ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) +ETC_GITCONFIG_SQ = \057etc/gitconfig DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) -template_dir_SQ = $(subst ','\'',$(template_dir)) +template_dir_SQ = \057share/git-core/templates prefix_SQ = $(subst ','\'',$(prefix)) sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) From 334cf5f96d18d4c97cb4f653cd5e9f14a85997ca Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 25 Oct 2007 00:15:21 +0200 Subject: [PATCH 0257/3720] git-gui: Protect against bad translation strings If a translation string uses a format character we don't have an argument for then it may throw an error when we attempt to format the translation. In this case switch back to the default format that comes with the program (aka the English translation). Signed-off-by: Shawn O. Pearce Signed-off-by: Steffen Prohaska --- git-gui/git-gui.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 9bc5626286..0547c3a624 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -88,13 +88,20 @@ if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} { package require msgcat -proc mc {fmt args} { - set fmt [::msgcat::mc $fmt] +proc _mc_trim {fmt} { set cmk [string first @@ $fmt] if {$cmk > 0} { - set fmt [string range $fmt 0 [expr {$cmk - 1}]] + return [string range $fmt 0 [expr {$cmk - 1}]] } - return [eval [list format $fmt] $args] + return $fmt +} + +proc mc {en_fmt args} { + set fmt [_mc_trim [::msgcat::mc $en_fmt]] + if {[catch {set msg [eval [list format $fmt] $args]} err]} { + set msg [eval [list format [_mc_trim $en_fmt]] $args] + } + return $msg } proc strcat {args} { From 4d2a9e8f6059753c549680e0b6f30a2dcbc73c08 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 25 Oct 2007 19:11:06 +0200 Subject: [PATCH 0258/3720] refactor help.c to git_install_prefix() and make_native_separator() git_install_prefix() returns the install prefix of msysgit. For all other architectures it returns "". The path returned contains slashes. make_native_separator() takes a unix path (slashes) and converts the separators in place. On Windows slashes are converted to backslashes. All the code was available in help.c and is now moved to path.c. The new function will be used to located the templates and /etc/gitconfig. Signed-off-by: Steffen Prohaska --- cache.h | 3 +++ help.c | 47 +++++------------------------------------------ path.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/cache.h b/cache.h index b7f57fdc2e..e87d0a350b 100644 --- a/cache.h +++ b/cache.h @@ -381,6 +381,9 @@ static inline int is_dev_null(const char *str) return !strcmp(str, "/dev/null"); } const char *make_absolute_path(const char *path); +/* Convert slashes in place. On Windows to backslashes. */ +char *make_native_separator(char *path); +const char *git_install_prefix(); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/help.c b/help.c index 1c0946c649..e59b856d9f 100644 --- a/help.c +++ b/help.c @@ -165,34 +165,6 @@ static void list_common_cmds_help(void) puts("(use 'git help -a' to get a list of all installed git commands)"); } -#ifdef __MINGW32__ -char* get_install_dir() -{ - static char* pgm = 0; - if (pgm) { - return pgm; - } else { - char* p; - int pgm_len = strlen(_pgmptr); - pgm = xmalloc(pgm_len + 1); - strcpy(pgm, _pgmptr); - p = strrchr(pgm, '\\'); /* \bin\ <- p */ - if (p) { - *p = '\0'; - p = strrchr(pgm, '\\'); /* \ <- p */ - if (p) { - *p = '\0'; - return pgm; - } - } - } - /* Note, according to the msdn documentation we have a full path - if started through the shell and this error should never happen. */ - fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); - exit(1); -} -#endif - static void show_man_page(const char *git_cmd) { const char *page; @@ -210,20 +182,11 @@ static void show_man_page(const char *git_cmd) #ifdef __MINGW32__ { - char* install_dir = get_install_dir(); - int install_dir_len = strlen(install_dir); - char* html_dir = "\\doc\\git\\html\\"; - int html_dir_len = strlen(html_dir); - char* suffix = ".html"; - int suffix_len = strlen(suffix); - int page_len = strlen(page); - int htmlpath_len = install_dir_len + html_dir_len + page_len + suffix_len; - char* htmlpath = xmalloc(htmlpath_len + 1); - strcpy (htmlpath, install_dir); - strcpy (htmlpath + install_dir_len, html_dir); - strcpy (htmlpath + install_dir_len + html_dir_len, page); - strcpy (htmlpath + install_dir_len + html_dir_len + page_len, suffix); - htmlpath[htmlpath_len] = 0; + const char *htmlpath = make_native_separator( + mkpath("%s/doc/git/html/%s.html" + , git_install_prefix() + , page) + ); printf("Launching default browser to display HTML help ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); } diff --git a/path.c b/path.c index 7a5ac5b067..e42b234fa1 100644 --- a/path.c +++ b/path.c @@ -370,3 +370,51 @@ const char *make_absolute_path(const char *path) return buf; } + +const char* git_install_prefix() +{ +#ifdef __MINGW32__ + static char* prefix; + + if (prefix) { + return prefix; + } + + char* p; + int pgm_len = strlen(_pgmptr); + prefix = xmalloc(pgm_len + 1); + strcpy(prefix, _pgmptr); + p = strrchr(prefix, '\\'); /* \bin\ <- p */ + if (p) { + *p = '\0'; + p = strrchr(prefix, '\\'); /* \ <- p */ + if (p) { + *p = '\0'; + for (p = prefix; *p; p++) + if (*p == '\\') + *p = '/'; + return prefix; + } + } + + /* Note, according to the msdn documentation we have a full path + if started through the shell and this error should never happen. */ + fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); + exit(1); +#else + return ""; +#endif +} + +char *make_native_separator(char* path) { +#ifdef __MINGW32__ + char* c; + for (c = path; *c; c++) { + if (*c == '/') + *c = '\\'; + } + return path; +#else + return path; +#endif +} From 0fbe22da392f39e1d144f78ef08b2dbdb882c164 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 25 Oct 2007 19:14:56 +0200 Subject: [PATCH 0259/3720] init: find template directory on Windows (msys) The template directory must be searched for using the full Windows path. But internally a Unix path starting with '/' is used. The internal Unix path is now prefixed with git_install_prefix() before accessing the file system Only absolute Unix paths are converted. Relative paths can be used as is. Signed-off-by: Steffen Prohaska --- builtin-init-db.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/builtin-init-db.c b/builtin-init-db.c index 5da2515f85..117fedd586 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -145,6 +145,17 @@ static void copy_templates(const char *git_dir, int len, const char *template_di template_dir = prefix_path(exec_path, strlen(exec_path), template_dir); } +#if __MINGW32__ + /* + * If it is an absolute Unix path it is prefixed with + * the git_install_prefix(). + */ + else if (template_dir[0] == '/') { + const char* prefix = git_install_prefix(); + template_dir = prefix_path(prefix, strlen(prefix), + template_dir); + } +#endif } strcpy(template_path, template_dir); template_len = strlen(template_path); From 636116b8a79c7c810afe8ae8e4c37e0a1de6f7b7 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 25 Oct 2007 19:16:11 +0200 Subject: [PATCH 0260/3720] config.c: find /etc/gitconfig on Windows (msys) /etc/gitconfig must be searched for using the full Windows path. But internally a Unix path starting with '/' is used. An absolute Unix path is now prefixed with git_install_prefix(). Signed-off-by: Steffen Prohaska --- config.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/config.c b/config.c index da2d1c1667..be0b1f0ed2 100644 --- a/config.c +++ b/config.c @@ -466,6 +466,17 @@ const char *git_etc_gitconfig(void) system_wide = prefix_path(exec_path, strlen(exec_path), system_wide); } +#if __MINGW32__ + /* + * If it is an absolute Unix path it is prefixed with + * the git_install_prefix(). + */ + else if (system_wide[0] == '/') { + const char* prefix = git_install_prefix(); + system_wide = prefix_path(prefix, strlen(prefix), + system_wide); + } +#endif } return system_wide; } From 1e65313ceb6bc5bf1574ae93335ec62a94d9ed7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 27 Oct 2007 20:26:31 +0700 Subject: [PATCH 0261/3720] spawnvppe_pipe: Don't overwrite argv[0] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because caller expects it so Signed-off-by: Nguyễn Thái Ngọc Duy --- spawn-pipe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spawn-pipe.c b/spawn-pipe.c index c8f0452823..3df7e22ed9 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -123,6 +123,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]) { const char *cmd_basename = strrchr(cmd, '/'); + const char *argv0 = argv[0]; pid_t pid; #ifdef __MINGW32__ @@ -214,6 +215,8 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, } #endif + argv[0] = argv0; + return pid; } From ee05d117627de156a70c9ff6c16341d0d2a42efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 27 Oct 2007 20:30:40 +0700 Subject: [PATCH 0262/3720] Rework quote_arg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MS Windows command line is handled in a weird way. This patch addresses: - Quote empty arguments - Only escape backslashes and double quotation marks inside quoted arguments - Quote arguments if they have asterisk or question marks to prevent expansion The last one is not documented in the link provided in the patch. I encountered that behavior on cmd.exe, Windows XP. MSYS not tested. Signed-off-by: Nguyễn Thái Ngọc Duy --- compat/mingw.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 22b5e1072e..90dc0805ae 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -303,6 +303,7 @@ void openlog(const char *ident, int option, int facility) { } +/* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx (Parsing C++ Command-Line Arguments */ static const char *quote_arg(const char *arg) { /* count chars to quote */ @@ -310,11 +311,23 @@ static const char *quote_arg(const char *arg) int force_quotes = 0; char *q, *d; const char *p = arg; + if (!*p) force_quotes = 1; while (*p) { - if (isspace(*p)) + if (isspace(*p) || *p == '*' || *p == '?') force_quotes = 1; - else if (*p == '"' || *p == '\\') + else if (*p == '"') n++; + else if (*p == '\\') { + int count = 0; + while (*p == '\\') { + count++; + p++; + len++; + } + if (*p == '"') + n += count*2 + 1; + continue; + } len++; p++; } @@ -325,8 +338,20 @@ static const char *quote_arg(const char *arg) d = q = xmalloc(len+n+3); *d++ = '"'; while (*arg) { - if (*arg == '"' || *arg == '\\') + if (*arg == '"') *d++ = '\\'; + else if (*arg == '\\') { + int count = 0; + while (*arg == '\\') { + count++; + *d++ = *arg++; + } + if (*arg == '"') { + while (count-- > 0) + *d++ = '\\'; + *d++ = '\\'; + } + } *d++ = *arg++; } *d++ = '"'; From eafce5ce148c553b2512ec87577cc43c15ea8ef8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 26 Oct 2007 22:27:45 +0200 Subject: [PATCH 0263/3720] Windows does not have mkdtemp. Signed-off-by: Johannes Sixt --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 7787607d49..97add19472 100644 --- a/Makefile +++ b/Makefile @@ -509,6 +509,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease + NO_MKDTEMP = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat From d3d5d0c2e55532839b1d0ad9e8b0c7d353fc51a7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 27 Oct 2007 23:21:20 +0200 Subject: [PATCH 0264/3720] Implement asynchronous functions using threads on Windows. A kill(2) is removed from upload-pack.c because we cannot assume that rev-list is run as a process. Signed-off-by: Johannes Sixt --- run-command.c | 29 ++++++++++++++++++++++++++++- run-command.h | 5 +++++ upload-pack.c | 5 +---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/run-command.c b/run-command.c index dca8626e22..d2e5f183d2 100644 --- a/run-command.c +++ b/run-command.c @@ -186,13 +186,23 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const return run_command(&cmd); } +#ifdef __MINGW32__ +static __stdcall unsigned run_thread(void *data) +{ + struct async *async = data; + return async->proc(async->fd_for_proc, async->data); +} +#endif + int start_async(struct async *async) { int pipe_out[2]; if (pipe(pipe_out) < 0) return error("cannot create pipe: %s", strerror(errno)); + async->out = pipe_out[0]; +#ifndef __MINGW32__ async->pid = fork(); if (async->pid < 0) { error("fork (async) failed: %s", strerror(errno)); @@ -203,16 +213,33 @@ int start_async(struct async *async) close(pipe_out[0]); exit(!!async->proc(pipe_out[1], async->data)); } - async->out = pipe_out[0]; close(pipe_out[1]); +#else + async->fd_for_proc = pipe_out[1]; + async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL); + if (!async->tid) { + error("cannot create thread: %s", strerror(errno)); + close_pair(pipe_out); + return -1; + } +#endif return 0; } int finish_async(struct async *async) { +#ifndef __MINGW32__ int ret = 0; if (wait_or_whine(async->pid)) ret = error("waitpid (async) failed"); +#else + DWORD ret = 0; + if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0) + ret = error("waiting for thread failed: %lu", GetLastError()); + else if (!GetExitCodeThread(async->tid, &ret)) + ret = error("cannot get thread exit code: %lu", GetLastError()); + CloseHandle(async->tid); +#endif return ret; } diff --git a/run-command.h b/run-command.h index 94e1e9d516..407d3c3bc3 100644 --- a/run-command.h +++ b/run-command.h @@ -59,7 +59,12 @@ struct async { int (*proc)(int fd, void *data); void *data; int out; /* caller reads from here and closes it */ +#ifndef __MINGW32__ pid_t pid; +#else + HANDLE tid; + int fd_for_proc; +#endif }; int start_async(struct async *async); diff --git a/upload-pack.c b/upload-pack.c index 369cb1f77c..0d7aa18bfe 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -170,11 +170,8 @@ static void create_pack_file(void) pack_objects.git_cmd = 1; pack_objects.argv = argv; - if (start_command(&pack_objects)) { - /* daemon sets things up to ignore TERM */ - kill(rev_list.pid, SIGKILL); + if (start_command(&pack_objects)) die("git-upload-pack: unable to fork git-pack-objects"); - } #ifndef __MINGW32__ /* We read from pack_objects.err to capture stderr output for From 36e0147fe5e941efb7f34f3d59845dbc9383ecd5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 Nov 2007 21:34:56 +0100 Subject: [PATCH 0265/3720] Move path handling functions from spawn-pipe.c to compat/mingw.c. Since these functions are MinGW-specific, they better belong into this compatibility file. They will be needed there in a follow-up change that reimplements execvp(). --- compat/mingw.c | 88 +++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 3 ++ spawn-pipe.c | 96 ++--------------------------------------------- 3 files changed, 94 insertions(+), 93 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 90dc0805ae..4b05718f03 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -441,6 +441,94 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) } } +static char *lookup_prog(const char *dir, const char *cmd, int tryexe) +{ + char path[MAX_PATH]; + snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); + + if (tryexe && access(path, 0) == 0) + return xstrdup(path); + path[strlen(path)-4] = '\0'; + if (access(path, 0) == 0) + return xstrdup(path); + return NULL; +} + +/* + * Determines the absolute path of cmd using the the split path in path. + * If cmd contains a slash or backslash, no lookup is performed. + */ +char *mingw_path_lookup(const char *cmd, char **path) +{ + char **p = path; + char *prog = NULL; + int len = strlen(cmd); + int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); + + if (strchr(cmd, '/') || strchr(cmd, '\\')) + prog = xstrdup(cmd); + + while (!prog && *p) { + prog = lookup_prog(*p++, cmd, tryexe); + } + if (!prog) { + prog = lookup_prog(".", cmd, tryexe); + if (!prog) + prog = xstrdup(cmd); + } + return prog; +} + +/* + * Splits the PATH into parts. + */ +char **mingw_get_path_split(void) +{ + char *p, **path, *envpath = getenv("PATH"); + int i, n = 0; + + if (!envpath || !*envpath) + return NULL; + + envpath = xstrdup(envpath); + p = envpath; + while (p) { + char *dir = p; + p = strchr(p, ';'); + if (p) *p++ = '\0'; + if (*dir) { /* not earlier, catches series of ; */ + ++n; + } + } + if (!n) + return NULL; + + path = xmalloc((n+1)*sizeof(char*)); + p = envpath; + i = 0; + do { + if (*p) + path[i++] = xstrdup(p); + p = p+strlen(p)+1; + } while (i < n); + path[i] = NULL; + + free(envpath); + + return path; +} + +void mingw_free_path_split(char **path) +{ + if (!path) + return; + + char **p = path; + while (*p) + free(*p++); + free(path); +} + int mingw_socket(int domain, int type, int protocol) { SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); diff --git a/git-compat-util.h b/git-compat-util.h index c6406d4379..f6deba520b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -499,6 +499,9 @@ int mingw_rename(const char*, const char*); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +extern char *mingw_path_lookup(const char *cmd, char **path); +extern char **mingw_get_path_split(void); +extern void mingw_free_path_split(char **path); /* Use git_lstat() instead of lstat()/stat() and * git_fstat() instead of fstat() on Windows diff --git a/spawn-pipe.c b/spawn-pipe.c index 3df7e22ed9..71232066c5 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -3,96 +3,6 @@ extern char **environ; -#ifdef __MINGW32__ -static char *lookup_prog(const char *dir, const char *cmd, int tryexe) -{ - char path[MAX_PATH]; - snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); - - if (tryexe && access(path, 0) == 0) - return xstrdup(path); - path[strlen(path)-4] = '\0'; - if (access(path, 0) == 0) - return xstrdup(path); - return NULL; -} - -/* - * Splits the PATH into parts. - */ -char **get_path_split() -{ - char *p, **path, *envpath = getenv("PATH"); - int i, n = 0; - - if (!envpath || !*envpath) - return NULL; - - envpath = xstrdup(envpath); - p = envpath; - while (p) { - char *dir = p; - p = strchr(p, ';'); - if (p) *p++ = '\0'; - if (*dir) { /* not earlier, catches series of ; */ - ++n; - } - } - if (!n) - return NULL; - - path = xmalloc((n+1)*sizeof(char*)); - p = envpath; - i = 0; - do { - if (*p) - path[i++] = xstrdup(p); - p = p+strlen(p)+1; - } while (i < n); - path[i] = NULL; - - free(envpath); - - return path; -} - -void free_path_split(char **path) -{ - if (!path) - return; - - char **p = path; - while (*p) - free(*p++); - free(path); -} - -/* - * Determines the absolute path of cmd using the the split path in path. - * If cmd contains a slash or backslash, no lookup is performed. - */ -static char *path_lookup(const char *cmd, char **path) -{ - char **p = path; - char *prog = NULL; - int len = strlen(cmd); - int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); - - if (strchr(cmd, '/') || strchr(cmd, '\\')) - prog = xstrdup(cmd); - - while (!prog && *p) { - prog = lookup_prog(*p++, cmd, tryexe); - } - if (!prog) { - prog = lookup_prog(".", cmd, tryexe); - if (!prog) - prog = xstrdup(cmd); - } - return prog; -} -#endif - /* cmd specifies the command to invoke. * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. * env specifies the environment. @@ -107,11 +17,11 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]) { #ifdef __MINGW32__ - char **path = get_path_split(); + char **path = mingw_get_path_split(); pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); - free_path_split(path); + mingw_free_path_split(path); #else pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout); #endif @@ -187,7 +97,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, } } - prog = path_lookup(cmd, path); + prog = mingw_path_lookup(cmd, path); interpr = parse_interpreter(prog); for (argc = 0; argv[argc];) argc++; From 2952476e8e9e4b0f455e1569a29e0d3930ee84b2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 Nov 2007 21:38:57 +0100 Subject: [PATCH 0266/3720] Reimplement execvp() such that it can invoke shell scripts. We conveniently reuse mingw_execve(), which does the shbang interpretation as well as other painful Windows compatibility stuff. --- compat/mingw.c | 14 ++++++++++++++ git-compat-util.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4b05718f03..4e1003442d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -529,6 +529,20 @@ void mingw_free_path_split(char **path) free(path); } +void mingw_execvp(const char *cmd, const char **argv) +{ + char **path = mingw_get_path_split(); + char *prog = mingw_path_lookup(cmd, path); + + if (prog) { + mingw_execve(prog, argv, (const char **) environ); + free(prog); + } else + errno = ENOENT; + + mingw_free_path_split(path); +} + int mingw_socket(int domain, int type, int protocol) { SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); diff --git a/git-compat-util.h b/git-compat-util.h index f6deba520b..148b64ab04 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -430,6 +430,8 @@ unsigned int alarm(unsigned int seconds); #include void mingw_execve(const char *cmd, const char **argv, const char **env); #define execve mingw_execve +extern void mingw_execvp(const char *cmd, const char **argv); +#define execvp mingw_execvp int fork(); typedef int pid_t; #define waitpid(pid, status, options) \ From 5f50b3edfa54d04fb751dc847687541a4c611f7c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:01:31 +0100 Subject: [PATCH 0267/3720] Revert "Returning -1 does not fail like it should in MSys." This reverts commit 327005a9ef9c3b784e4742cece0710de6a549313. git-config should print a message and exit with error if --file is used and the file provided does not exist. This was not the case. The problem was introduced by the reverted commit. Signed-off-by: Steffen Prohaska --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.c b/config.c index 0badbeb62e..edea061892 100644 --- a/config.c +++ b/config.c @@ -443,7 +443,7 @@ int git_config_from_file(config_fn_t fn, const char *filename) int ret; FILE *f = fopen(filename, "r"); - ret = 1; + ret = -1; if (f) { config_file = f; config_file_name = filename; From c1561567eff8ae46e88aadc51c7f5062cca34776 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:14:27 +0100 Subject: [PATCH 0268/3720] fix warning (printf format) Signed-off-by: Steffen Prohaska --- builtin-ls-files.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index b70da1863b..b55c79ec1a 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -208,7 +208,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) if (!show_stage) { fputs(tag, stdout); } else { - printf("%s%06o %s %d\t", + printf("%s%06lo %s %d\t", tag, ntohl(ce->ce_mode), abbrev ? find_unique_abbrev(ce->sha1,abbrev) From 156d5a32ad4dc70460a62980547bcfda788ace58 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:17:31 +0100 Subject: [PATCH 0269/3720] fix warning (const ptr) Signed-off-by: Steffen Prohaska --- exec_cmd.c | 4 ++-- run-command.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 6aa842bb4f..a2d82d3311 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -121,7 +121,7 @@ int execv_git_cmd(const char **argv) trace_argv_printf(argv, -1, "trace: exec:"); /* execvp() can only ever return if it fails */ - execvp(cmd.buf, (char **)argv); + execvp(cmd.buf, argv); trace_printf("trace: exec failed: %s\n", strerror(errno)); @@ -175,7 +175,7 @@ int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) trace_argv_printf(argv, -1, "trace: exec:"); - pid = spawnvpe_pipe(cmd.buf, argv, environ, + pid = spawnvpe_pipe(cmd.buf, argv, (const char **)environ, pin, pout); argv[0] = tmp; diff --git a/run-command.c b/run-command.c index d2e5f183d2..822449c5f5 100644 --- a/run-command.c +++ b/run-command.c @@ -15,7 +15,7 @@ int start_command(struct child_process *cmd) int fdin[2] = { -1, -1 }; int fdout[2] = { -1, -1 }; int fderr[2] = { -1, -1 }; - char **env = environ; + const char **env = (const char **)environ; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { From e169a6e89f8b9affc8131e3b3b0752064c1dbc86 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:24:08 +0100 Subject: [PATCH 0270/3720] fix warning (unitialized variable) Signed-off-by: Steffen Prohaska --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transport.c b/transport.c index 5132d289da..d44fe7cee7 100644 --- a/transport.c +++ b/transport.c @@ -107,7 +107,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list) return; for (;;) { - int cmp, len; + int cmp = cmp, len; if (!fgets(buffer, sizeof(buffer), f)) { fclose(f); From 0f2bc7c7d28274ba2e130a03817c9ca2d677901e Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:27:12 +0100 Subject: [PATCH 0271/3720] fix warning (unused variable) --- upload-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upload-pack.c b/upload-pack.c index 0d7aa18bfe..e004c024cd 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -142,7 +142,7 @@ static void create_pack_file(void) struct async rev_list; struct child_process pack_objects; int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); - char data[8193], progress[128]; + char data[8193]; char abort_msg[] = "aborting due to possible repository " "corruption on the remote side."; int buffered = -1; From e176f0fb1519dc1a9c3e55aa00f03ffb85fc3143 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:32:18 +0100 Subject: [PATCH 0272/3720] fix warning (int used as pointer) Signed-off-by: Steffen Prohaska --- test-chmtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-chmtime.c b/test-chmtime.c index b6dc548a2a..8a1e6b8479 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -22,7 +22,7 @@ int git_utime (const char *file_name, const struct utimbuf *times) time_t_to_filetime(times->modtime, &mft); time_t_to_filetime(times->actime, &aft); - if (!SetFileTime(_get_osfhandle(fh), NULL, &aft, &mft)) { + if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { errno = EINVAL; rc = -1; } else From 0ed5d28283854fc47f130d65f6b658398eef80d8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Sep 2007 17:36:47 +0100 Subject: [PATCH 0273/3720] MinGW: Convert CR/LF to LF in tag signatures On Windows, gpg outputs CR/LF signatures. But since the tag messages are already stripped of the CR by stripspace(), it is arguably nicer to do the same for the tag signature. Actually, this patch does not look for CR/LF, but strips all CRs from the signature. [ sp: ported code to use strbuf ] Signed-off-by: Johannes Schindelin Signed-off-by: Steffen Prohaska --- builtin-tag.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/builtin-tag.c b/builtin-tag.c index 66e5a58307..ae8538897b 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -224,6 +224,20 @@ static int do_sign(struct strbuf *buffer) if (len < 0) return error("could not read the entire signature from gpg."); +#ifdef __MINGW32__ + /* strip CR from the line endings */ + { + int i, j; + for (i = j = 0; i < buffer->len; i++) + if (buffer->buf[i] != '\r') { + if (i != j) + buffer->buf[j] = buffer->buf[i]; + j++; + } + strbuf_setlen(buffer, j); + } +#endif + return 0; } From 24737fec8695e6c4aa569fbb39d83c950a276844 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 20 Oct 2007 21:59:28 +0200 Subject: [PATCH 0274/3720] git remote does not work from the t/ directory - skip the test. --- t/t5505-remote.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 636aec2f71..a56e5a32c2 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -4,6 +4,9 @@ test_description='git remote porcelain-ish' . ./test-lib.sh +say "git remote does not work in t/ - skipping" +test_done + GIT_CONFIG=.git/config export GIT_CONFIG From c2822f9d935cb75e759de0039840570cb91c1c08 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 6 Nov 2007 08:26:42 +0100 Subject: [PATCH 0275/3720] Exclude some stuff from Windows header files. There happens to be a name clash on 'boolean' in test-parse-options.c with a type defined one of Windows's OLE header files (rpcndr.h). Since we don't need that anyway, -DNOGDI does not pull those headers in. Signed-off-by: Johannes Sixt --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e1fe7779ac..5cb6a31743 100644 --- a/Makefile +++ b/Makefile @@ -511,7 +511,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe From a67246dc8aa004c6aaa0060f04e6fda427099079 Mon Sep 17 00:00:00 2001 From: Brian Gernhardt Date: Sun, 4 Nov 2007 10:31:26 -0500 Subject: [PATCH 0276/3720] t3502: Disambiguate between file and rev by adding -- On a case insensitive file system, this test fails because git-diff doesn't know if it is asking for the file "A" or the tag "a". Adding "--" at the end of the ambiguous commands allows the test to finish properly. Signed-off-by: Brian Gernhardt Signed-off-by: Junio C Hamano --- t/t3502-cherry-pick-merge.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t3502-cherry-pick-merge.sh b/t/t3502-cherry-pick-merge.sh index 3274c6141b..7c92e261fc 100755 --- a/t/t3502-cherry-pick-merge.sh +++ b/t/t3502-cherry-pick-merge.sh @@ -36,7 +36,7 @@ test_expect_success 'cherry-pick a non-merge with -m should fail' ' git reset --hard && git checkout a^0 && ! git cherry-pick -m 1 b && - git diff --exit-code a + git diff --exit-code a -- ' @@ -45,7 +45,7 @@ test_expect_success 'cherry pick a merge without -m should fail' ' git reset --hard && git checkout a^0 && ! git cherry-pick c && - git diff --exit-code a + git diff --exit-code a -- ' @@ -98,7 +98,7 @@ test_expect_success 'revert a merge (1)' ' git reset --hard && git checkout c^0 && git revert -m 1 c && - git diff --exit-code a + git diff --exit-code a -- ' @@ -107,7 +107,7 @@ test_expect_success 'revert a merge (2)' ' git reset --hard && git checkout c^0 && git revert -m 2 c && - git diff --exit-code b + git diff --exit-code b -- ' From 9dcfde61ed7334e925fca7e62dbb5791547a5f5b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 4 Nov 2007 23:50:23 +0100 Subject: [PATCH 0277/3720] help: Teach help to try harder to locate help Help now tries to takes the argument as is and prefixed with "git-". If no html page is found an error is reported. With this change you can run "git help user-manual". Signed-off-by: Steffen Prohaska --- help.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/help.c b/help.c index b81ddf0fb5..02e59b75e0 100644 --- a/help.c +++ b/help.c @@ -7,6 +7,7 @@ #include "builtin.h" #include "exec_cmd.h" #include "common-cmds.h" +#include "dir.h" //#include /* most GUI terminals set COLUMNS (although some don't export it) */ @@ -242,6 +243,29 @@ void list_common_cmds_help(void) static void show_man_page(const char *git_cmd) { +#ifdef __MINGW32__ + { + char *htmlpath = make_native_separator( + mkpath("%s/doc/git/html/%s.html" + , git_install_prefix() + , git_cmd) + ); + if (!file_exists(htmlpath)) { + htmlpath = make_native_separator( + mkpath("%s/doc/git/html/git-%s.html" + , git_install_prefix() + , git_cmd) + ); + if (!file_exists(htmlpath)) { + fprintf(stderr, "Can't find help for '%s'.\n" + , git_cmd); + exit(1); + } + } + printf("Launching default browser to display HTML help ...\n"); + ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); + } +#else const char *page; if (!prefixcmp(git_cmd, "git")) @@ -255,17 +279,6 @@ static void show_man_page(const char *git_cmd) page = p; } -#ifdef __MINGW32__ - { - const char *htmlpath = make_native_separator( - mkpath("%s/doc/git/html/%s.html" - , git_install_prefix() - , page) - ); - printf("Launching default browser to display HTML help ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); - } -#else execlp("man", "man", page, NULL); #endif } From 89e51c31058fde41a9bdf7ed4e3aa6dd50caca3b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 11 Nov 2007 21:36:19 +0100 Subject: [PATCH 0278/3720] Revert NO_ETC_PASSWD hack. This hack was introduced to work around missing Unix-like user database. But it turns out that the functionality required can easily be faked, Which happens in a follow-up patch. --- Makefile | 3 +-- git-compat-util.h | 3 --- ident.c | 13 ------------- path.c | 11 ----------- 4 files changed, 1 insertion(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 7add7b4fb8..0dc4200561 100644 --- a/Makefile +++ b/Makefile @@ -500,7 +500,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_CURL=YesPlease NO_SYMLINK_HEAD=YesPlease NO_IPV6=YesPlease - NO_ETC_PASSWD=YesPlease NO_SETENV=YesPlease NO_UNSETENV=YesPlease NO_STRCASESTR=YesPlease @@ -513,7 +512,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat + COMPAT_CFLAGS += -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe diff --git a/git-compat-util.h b/git-compat-util.h index 7cf6269c42..66c4fb37a5 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -63,8 +63,6 @@ int mkstemp (char *__template); #include #include #include -#endif -#ifndef NO_ETC_PASSWD #include #include #include @@ -431,7 +429,6 @@ int symlink(const char *oldpath, const char *newpath); int fchmod(int fildes, mode_t mode); int lstat(const char *file_name, struct stat *buf); -/* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ int socketpair(int d, int type, int protocol, int sv[2]); #define AF_UNIX 0 #define SOCK_STREAM 0 diff --git a/ident.c b/ident.c index 1f99984d76..9b2a852cb0 100644 --- a/ident.c +++ b/ident.c @@ -9,8 +9,6 @@ static char git_default_date[50]; -#ifndef NO_ETC_PASSWD - static void copy_gecos(const struct passwd *w, char *name, size_t sz) { char *src, *dst; @@ -72,11 +70,8 @@ static void copy_email(const struct passwd *pw) } } -#endif - static void setup_ident(void) { -#ifndef NO_ETC_PASSWD struct passwd *pw = NULL; /* Get the name ("gecos") */ @@ -101,7 +96,6 @@ static void setup_ident(void) copy_email(pw); } } -#endif /* And set the default date */ if (!git_default_date[0]) @@ -212,9 +206,7 @@ const char *fmt_ident(const char *name, const char *email, email = git_default_email; if (!*name) { -#ifndef NO_ETC_PASSWD struct passwd *pw; -#endif if (0 <= error_on_no_name && name == git_default_name && env_hint) { @@ -223,16 +215,11 @@ const char *fmt_ident(const char *name, const char *email, } if (0 < error_on_no_name) die("empty ident %s <%s> not allowed", name, email); -#ifndef NO_ETC_PASSWD pw = getpwuid(getuid()); if (!pw) die("You don't exist. Go away!"); strlcpy(git_default_name, pw->pw_name, sizeof(git_default_name)); -#else - strlcpy(git_default_name, "unknown", - sizeof(git_default_name)); -#endif name = git_default_name; } diff --git a/path.c b/path.c index 2c5ebfb922..e264bb34a9 100644 --- a/path.c +++ b/path.c @@ -141,8 +141,6 @@ int validate_headref(const char *path) return -1; } -#ifndef NO_ETC_PASSWD - static char *user_path(char *buf, char *path, int sz) { struct passwd *pw; @@ -182,15 +180,6 @@ static char *user_path(char *buf, char *path, int sz) return buf; } -#else - -static char *user_path(char *buf, char *path, int sz) -{ - return getenv("HOME"); -} - -#endif - /* * First, one directory to try is determined by the following algorithm. * From 50d1c4c74552c97464536a17a45aba2f12facbec Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 08:07:00 +0100 Subject: [PATCH 0279/3720] Fake implementions of getpwuid(), getuid(), and getpwnam(). getpwuid() is kept as simple as possible so that no errors are generated. Since the information that it returns is not very useful, users are still required to set up user.name and user.email configuration. All uses of getpwuid() are like getpwuid(getuid()), hence, the return value of getpwuid() is irrelevant. getpwnam() is only used to resolve '~' and '~username' paths, which is an idiom not known on Windows, hence, we don't implement it, either. Signed-off-by: Johannes Sixt --- compat/mingw.c | 14 ++++++++++++++ git-compat-util.h | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4e1003442d..152915fd21 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -620,3 +620,17 @@ int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) } while (len < 0); return len; } + +struct passwd *mingw_getpwuid(int uid) +{ + static char user_name[100]; + static struct passwd p; + + DWORD len = sizeof(user_name); + if (!GetUserName(user_name, &len)) + return NULL; + p.pw_name = user_name; + p.pw_gecos = "unknown"; + p.pw_dir = NULL; + return &p; +} diff --git a/git-compat-util.h b/git-compat-util.h index 66c4fb37a5..79ce4e0c2f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -527,6 +527,16 @@ int git_fstat(int fd, struct stat *buf); int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); #define vsnprintf mingw_vsnprintf +struct passwd { + char *pw_name; + char *pw_gecos; + char *pw_dir; +}; +struct passwd *mingw_getpwuid(int uid); +#define getpwuid mingw_getpwuid +static inline int getuid() { return 1; } +static inline struct passwd *getpwnam(const char *name) { return NULL; } + #endif /* __MINGW32__ */ #endif From a23a15abc656e26e9f75c7943f7be9d64f6c801f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 12:41:53 +0100 Subject: [PATCH 0280/3720] Use Windows's native API instead of stat() in rename()'s error path. Since we are only interested whether the named entry is a directory, it is sufficient to use GetFileAttributes() instead of a full stat() call. --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 152915fd21..412cdd6f5a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -577,8 +577,8 @@ int mingw_rename(const char *pold, const char *pnew) return 0; /* TODO: translate more errors */ if (GetLastError() == ERROR_ACCESS_DENIED) { - struct stat st; - if (!stat(pnew, &st) && S_ISDIR(st.st_mode)) { + DWORD attrs = GetFileAttributes(pnew); + if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { errno = EISDIR; return -1; } From e569ab2ae74ed3b87196e26d8b9ac08296734225 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 12:52:41 +0100 Subject: [PATCH 0281/3720] Use a customized struct stat that also has the st_blocks member. Windows's struct stat does not have a st_blocks member. Since we already have our own stat/lstat/fstat implementations, we can just as well use a customized struct stat. This patch introduces just that, and also fills in the st_blocks member. On the other hand, we don't provide members that are never used. Signed-off-by: Johannes Sixt --- compat/mingw.c | 38 +++++++++++++++++++++++++++++--------- git-compat-util.h | 24 +++++++++++++++++------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 412cdd6f5a..f464fdb63d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -31,6 +31,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } +static inline size_t size_to_blocks(size_t s) +{ + return (s+511)/512; +} + extern int _getdrive( void ); /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In @@ -52,10 +57,10 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; - buf->st_nlink = 1; buf->st_mode = fMode; buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_blocks = size_to_blocks(buf->st_size); + buf->st_dev = _getdrive() - 1; buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); @@ -86,10 +91,10 @@ static int do_lstat(const char *file_name, struct stat *buf) /* We provide our own lstat/fstat functions, since the provided * lstat/fstat functions are so slow. These stat functions are * tailored for Git's usage (read: fast), and are not meant to be - * complete. Note that Git stat()s are redirected to git_lstat() + * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int git_lstat(const char *file_name, struct stat *buf) +int mingw_lstat(const char *file_name, struct mingw_stat *buf) { int namelen; static char alt_name[PATH_MAX]; @@ -117,7 +122,8 @@ int git_lstat(const char *file_name, struct stat *buf) } #undef fstat -int git_fstat(int fd, struct stat *buf) +#undef stat +int mingw_fstat(int fd, struct mingw_stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); BY_HANDLE_FILE_INFORMATION fdata; @@ -127,8 +133,22 @@ int git_fstat(int fd, struct stat *buf) return -1; } /* direct non-file handles to MS's fstat() */ - if (GetFileType(fh) != FILE_TYPE_DISK) - return fstat(fd, buf); + if (GetFileType(fh) != FILE_TYPE_DISK) { + struct stat st; + if (fstat(fd, &st)) + return -1; + buf->st_ino = st.st_ino; + buf->st_gid = st.st_gid; + buf->st_uid = st.st_uid; + buf->st_mode = st.st_mode; + buf->st_size = st.st_size; + buf->st_blocks = size_to_blocks(buf->st_size); + buf->st_dev = st.st_dev; + buf->st_atime = st.st_atime; + buf->st_mtime = st.st_mtime; + buf->st_ctime = st.st_ctime; + return 0; + } if (GetFileInformationByHandle(fh, &fdata)) { int fMode = S_IREAD; @@ -142,10 +162,10 @@ int git_fstat(int fd, struct stat *buf) buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; - buf->st_nlink = 1; buf->st_mode = fMode; buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_blocks = size_to_blocks(buf->st_size); + buf->st_dev = _getdrive() - 1; buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); diff --git a/git-compat-util.h b/git-compat-util.h index 79ce4e0c2f..71887ee6ae 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -515,14 +515,24 @@ extern char *mingw_path_lookup(const char *cmd, char **path); extern char **mingw_get_path_split(void); extern void mingw_free_path_split(char **path); -/* Use git_lstat() instead of lstat()/stat() and - * git_fstat() instead of fstat() on Windows +/* Use mingw_lstat() instead of lstat()/stat() and + * mingw_fstat() instead of fstat() on Windows. + * struct stat is redefined because it lacks the st_blocks member. */ -int git_lstat(const char *file_name, struct stat *buf); -int git_fstat(int fd, struct stat *buf); -#define lstat(x,y) git_lstat(x,y) -#define stat(x,y) git_lstat(x,y) -#define fstat(x,y) git_fstat(x,y) +struct mingw_stat { + unsigned st_mode; + time_t st_mtime, st_atime, st_ctime; + unsigned st_dev, st_ino, st_uid, st_gid; + size_t st_size; + size_t st_blocks; +}; +int mingw_lstat(const char *file_name, struct mingw_stat *buf); +int mingw_fstat(int fd, struct mingw_stat *buf); +#define fstat mingw_fstat +#define lstat mingw_lstat +#define stat mingw_stat +static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) +{ return mingw_lstat(file_name, buf); } int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); #define vsnprintf mingw_vsnprintf From dbdc65fe2db3ec5137081bc4d72d518bb65cffd3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 12:51:35 +0100 Subject: [PATCH 0282/3720] Revert the NO_ST_BLOCKS hack. This conditional was needed to work around the missing st_blocks member in Windows's struct stat. --- Makefile | 2 +- builtin-count-objects.c | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 0dc4200561..ff2a5ed787 100644 --- a/Makefile +++ b/Makefile @@ -512,7 +512,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat + COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe diff --git a/builtin-count-objects.c b/builtin-count-objects.c index 762c024279..f00306fb67 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -43,11 +43,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, if (lstat(path, &st) || !S_ISREG(st.st_mode)) bad = 1; else -#ifndef NO_ST_BLOCKS (*loose_size) += xsize_t(st.st_blocks); -#else - (*loose_size) += xsize_t((st.st_size+511)/512); -#endif } if (bad) { if (verbose) { From e0c9a54e11e1acf965b43c6abfac7a883a8565ed Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 13:00:06 +0100 Subject: [PATCH 0283/3720] Clean up some dummy compatibility implementations. In particular, sync() was never declared and caused a warning. --- compat/mingw.c | 4 ---- git-compat-util.h | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f464fdb63d..befdb147ca 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -315,10 +315,6 @@ char *mingw_getcwd(char *pointer, int len) return ret; } -void sync(void) -{ -} - void openlog(const char *ident, int option, int facility) { } diff --git a/git-compat-util.h b/git-compat-util.h index 71887ee6ae..d0c0884fc9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -505,9 +505,9 @@ int mingw_socket(int domain, int type, int protocol); int mingw_rename(const char*, const char*); #define rename mingw_rename -#define setlinebuf(x) -#define fsync(x) 0 -#define getppid() 1 +static inline int fsync(int fd) { return 0; } +static inline int getppid(void) { return 1; } +static inline void sync(void) {} extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From 73c1250e77f52dfe1b0bddb6eaf20532d1de58b2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 15:08:18 +0100 Subject: [PATCH 0284/3720] Declare getpagesize() - gcc provides it for us. It is in MinGW's libgcc.a, which appearently is always linked in. Signed-off-by: Johannes Sixt --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index d0c0884fc9..d85fdf5415 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -508,6 +508,7 @@ int mingw_rename(const char*, const char*); static inline int fsync(int fd) { return 0; } static inline int getppid(void) { return 1; } static inline void sync(void) {} +extern int getpagesize(void); /* defined in MinGW's libgcc.a */ extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From 6d305e33413451a26a38e82a863685fb11bc6cba Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 10:14:45 +0100 Subject: [PATCH 0285/3720] Implement setitimer() and sigaction(). The timer is implemented using a thread. Signed-off-by: Johannes Sixt --- compat/mingw.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 19 +++++++- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index befdb147ca..eaf6267025 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -650,3 +650,119 @@ struct passwd *mingw_getpwuid(int uid) p.pw_dir = NULL; return &p; } + + +static HANDLE timer_event; +static HANDLE timer_thread; +static int timer_interval; +static int one_shot; +static sig_handler_t timer_fn = SIG_DFL; + +/* The timer works like this: + * The thread, ticktack(), is basically a trivial routine that most of the + * time only waits to receive the signal to terminate. The main thread + * tells the thread to terminate by setting the timer_event to the signalled + * state. + * But ticktack() does not wait indefinitely; instead, it interrupts the + * wait state every now and then, namely exactly after timer's interval + * length. At these opportunities it calls the signal handler. + */ + +static __stdcall unsigned ticktack(void *dummy) +{ + while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { + if (timer_fn == SIG_DFL) + die("Alarm"); + if (timer_fn != SIG_IGN) + timer_fn(SIGALRM); + if (one_shot) + break; + } + return 0; +} + +static int start_timer_thread(void) +{ + timer_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (timer_event) { + timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL); + if (!timer_thread ) + return errno = ENOMEM, + error("cannot create progress indicator"); + } else + return errno = ENOMEM, + error("cannot allocate resources for progress indicator"); + return 0; +} + +static void stop_timer_thread(void) +{ + if (timer_event) + SetEvent(timer_event); /* tell thread to terminate */ + if (timer_thread) { + int rc = WaitForSingleObject(timer_thread, 1000); + if (rc == WAIT_TIMEOUT) + error("timer thread did not terminate timely"); + else if (rc != WAIT_OBJECT_0) + error("waiting for timer thread failed: %lu", + GetLastError()); + CloseHandle(timer_thread); + } + if (timer_event) + CloseHandle(timer_event); + timer_event = NULL; + timer_thread = NULL; +} + +static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2) +{ + return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec; +} + +int setitimer(int type, struct itimerval *in, struct itimerval *out) +{ + static const struct timeval zero; + + if (out != NULL) + return errno = EINVAL, + error("setitmer param 3 != NULL not implemented"); + if (!is_timeval_eq(&in->it_interval, &zero) && + !is_timeval_eq(&in->it_interval, &in->it_value)) + return errno = EINVAL, + error("setitmer: it_interval must be zero or eq it_value"); + + if (timer_thread) + stop_timer_thread(); + + if (is_timeval_eq(&in->it_value, &zero) && + is_timeval_eq(&in->it_interval, &zero)) + return 0; + + timer_interval = in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000; + one_shot = is_timeval_eq(&in->it_value, &zero); + atexit(stop_timer_thread); + return start_timer_thread(); +} + +int sigaction(int sig, struct sigaction *in, struct sigaction *out) +{ + if (sig != SIGALRM) + return errno = EINVAL, + error("sigaction only implemented for SIGALRM"); + if (out != NULL) + return errno = EINVAL, + error("sigaction: param 3 != NULL not implemented"); + + timer_fn = in->sa_handler; + return 0; +} + +#undef signal +sig_handler_t mingw_signal(int sig, sig_handler_t handler) +{ + if (sig != SIGALRM) + return signal(sig, handler); + sig_handler_t old = timer_fn; + timer_fn = handler; + return old; +} diff --git a/git-compat-util.h b/git-compat-util.h index d85fdf5415..bdda57221a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -454,7 +454,6 @@ typedef int pid_t; #define WNOHANG 1 #define SIGKILL 0 #define SIGCHLD 0 -#define SIGALRM 0 #define SIGPIPE 0 #define ECONNABORTED 0 @@ -548,6 +547,24 @@ struct passwd *mingw_getpwuid(int uid); static inline int getuid() { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } +struct itimerval { + struct timeval it_value, it_interval; +}; +int setitimer(int type, struct itimerval *in, struct itimerval *out); +#define ITIMER_REAL 0 + +typedef void (__cdecl *sig_handler_t)(int); +struct sigaction { + sig_handler_t sa_handler; + unsigned sa_flags; +}; +int sigaction(int sig, struct sigaction *in, struct sigaction *out); +#define sigemptyset(x) (void)0 +#define SA_RESTART 0 +#define SIGALRM 100 +sig_handler_t mingw_signal(int sig, sig_handler_t handler); +#define signal mingw_signal + #endif /* __MINGW32__ */ #endif From 2b3d05218b6184c655507673b03d923e0c9ae4d6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 22:27:06 +0100 Subject: [PATCH 0286/3720] Revert "Make the progress indicator work when the total runtime is unknown." This reverts commit ddb51d3baf427a9c38ae1d297eb07daae338536f, we don't need it anymore, now that we have an implementation for timers. --- progress.c | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/progress.c b/progress.c index 0e57fe705c..3f6a602a53 100644 --- a/progress.c +++ b/progress.c @@ -37,26 +37,13 @@ struct progress { static volatile sig_atomic_t progress_update; -#ifndef __MINGW32__ static void progress_interval(int signum) { progress_update = 1; } -#else -static HANDLE progress_event; -static HANDLE progress_thread; - -static __stdcall unsigned heartbeat(void *dummy) -{ - while (WaitForSingleObject(progress_event, 1000) == WAIT_TIMEOUT) - progress_update = 1; - return 0; -} -#endif static void set_progress_signal(void) { -#ifndef __MINGW32__ struct sigaction sa; struct itimerval v; @@ -72,43 +59,13 @@ static void set_progress_signal(void) v.it_interval.tv_usec = 0; v.it_value = v.it_interval; setitimer(ITIMER_REAL, &v, NULL); -#else - /* this is just eye candy: errors are not fatal */ - progress_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (progress_event) { - progress_thread = (HANDLE) _beginthreadex(NULL, 0, heartbeat, NULL, 0, NULL); - if (!progress_thread ) - error("cannot create progress indicator"); - } else - error("cannot allocate resources for progress indicator"); -#endif } static void clear_progress_signal(void) { -#ifndef __MINGW32__ struct itimerval v = {{0,},}; setitimer(ITIMER_REAL, &v, NULL); signal(SIGALRM, SIG_IGN); -#else - /* this is just eye candy: errors are not fatal */ - if (progress_event) - SetEvent(progress_event); /* tells thread to terminate */ - if (progress_thread) { - int rc = WaitForSingleObject(progress_thread, 1000); - if (rc == WAIT_TIMEOUT) - error("progress thread did not terminate timely"); - else if (rc != WAIT_OBJECT_0) - error("waiting for progress thread failed: %lu", - GetLastError()); - CloseHandle(progress_thread); - } - if (progress_event) - CloseHandle(progress_event); - progress_event = NULL; - progress_thread = NULL; -#endif - progress_update = 0; } From 3e0ba4ccdc1f4058a31eacb2f6ccca1ffa094e5a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 15:44:48 +0100 Subject: [PATCH 0287/3720] Clean up cruft from the MINGW32 section of git-compat-util.h Quite a lot of stuff has accumulated or is now obsolete. The stubs of POSIX functions that are not implemented or that always fail are now implemented as inline functions so that they exist in only one place. --- compat/mingw.c | 43 ---------------------------------------- git-compat-util.h | 50 +++++++++++++++++++++++------------------------ 2 files changed, 24 insertions(+), 69 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index eaf6267025..63c632adaf 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,28 +1,8 @@ #include -#include -#include #include "../git-compat-util.h" unsigned int _CRT_fmode = _O_BINARY; -int readlink(const char *path, char *buf, size_t bufsiz) -{ - errno = ENOSYS; - return -1; -} - -int symlink(const char *oldpath, const char *newpath) -{ - errno = ENOSYS; - return -1; -} - -int fchmod(int fildes, mode_t mode) -{ - errno = EBADF; - return -1; -} - static inline time_t filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; @@ -175,29 +155,6 @@ int mingw_fstat(int fd, struct mingw_stat *buf) return -1; } -/* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ -int socketpair(int d, int type, int protocol, int sv[2]) -{ - return -1; -} -int syslog(int type, char *bufp, ...) -{ - return -1; -} -unsigned int alarm(unsigned int seconds) -{ - return 0; -} -#include -int fork() -{ - return -1; -} - -int kill(pid_t pid, int sig) -{ - return -1; -} unsigned int sleep (unsigned int __seconds) { Sleep(__seconds*1000); diff --git a/git-compat-util.h b/git-compat-util.h index bdda57221a..bfdee76749 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -407,46 +407,46 @@ static inline int strtol_i(char const *s, int base, int *result) #ifdef __MINGW32__ -#ifndef S_ISLNK +#include + #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 -#endif - -#ifndef S_ISGRP -#define S_ISGRP(x) 0 #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 #define S_ISGID 0 #define S_IROTH 0 #define S_IXOTH 0 -#endif -int readlink(const char *path, char *buf, size_t bufsiz); -int symlink(const char *oldpath, const char *newpath); -#define link symlink -int fchmod(int fildes, mode_t mode); -int lstat(const char *file_name, struct stat *buf); +static inline int readlink(const char *path, char *buf, size_t bufsiz) +{ errno = ENOSYS; return -1; } +static inline int symlink(const char *oldpath, const char *newpath) +{ errno = ENOSYS; return -1; } +static inline int link(const char *oldpath, const char *newpath) +{ errno = ENOSYS; return -1; } +static inline int fchmod(int fildes, mode_t mode) +{ errno = ENOSYS; return -1; } +static inline int fork(void) +{ errno = ENOSYS; return -1; } +static inline int kill(pid_t pid, int sig) +{ errno = ENOSYS; return -1; } +static inline unsigned int alarm(unsigned int seconds) +{ return 0; } -int socketpair(int d, int type, int protocol, int sv[2]); -#define AF_UNIX 0 -#define SOCK_STREAM 0 -int syslog(int type, char *bufp, ...); -#define LOG_ERR 1 -#define LOG_INFO 2 -#define LOG_DAEMON 4 -unsigned int alarm(unsigned int seconds); -#include void mingw_execve(const char *cmd, const char **argv, const char **env); #define execve mingw_execve extern void mingw_execvp(const char *cmd, const char **argv); #define execvp mingw_execvp -int fork(); typedef int pid_t; -#define waitpid(pid, status, options) \ - ((options == 0) ? _cwait((status), (pid), 0) \ - : (errno = EINVAL, -1)) +static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +{ + if (options == 0) + return _cwait(status, pid, 0); + else + return errno = EINVAL, -1; +} + #define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ #define WEXITSTATUS(x) ((x) & 0xff) #define WIFSIGNALED(x) ((unsigned)(x) > 259) @@ -455,9 +455,7 @@ typedef int pid_t; #define SIGKILL 0 #define SIGCHLD 0 #define SIGPIPE 0 -#define ECONNABORTED 0 -int kill(pid_t pid, int sig); unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); From cf1fd675d2fb05c46ea472bbb3266985b63fbf01 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 16:57:47 +0100 Subject: [PATCH 0288/3720] Implement a stub for fcntl(). This stub does nothing for F_GETFD and F_SETFD, and fails for all other commands. Signed-off-by: Johannes Sixt --- git-compat-util.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index bfdee76749..85b5d8806a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -563,6 +563,13 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out); sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +#define F_GETFD 1 +#define F_SETFD 2 +#define FD_CLOEXEC 0x1 +static inline int mingw_fcntl(int fd, int cmd, long arg) +{ return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } +#define fcntl mingw_fcntl + #endif /* __MINGW32__ */ #endif From 0102b1b02ea59cafbfa72fb16f4359387154094a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 17:02:09 +0100 Subject: [PATCH 0289/3720] Revert "Windows does not have the close-on-exec flag." This reverts commit e7a70c5ddfa0f925760c131c2c60c25b814df222. We now have a fcntl stub that makes the bracketed piece of code a no-op. --- sha1_file.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index 0e527f7c6f..1df56aa417 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -653,7 +653,6 @@ static int open_packed_git_1(struct packed_git *p) } else if (p->pack_size != st.st_size) return error("packfile %s size changed", p->pack_name); -#ifndef __MINGW32__ /* We leave these file descriptors open with sliding mmap; * there is no point keeping them open across exec(), though. */ @@ -663,7 +662,6 @@ static int open_packed_git_1(struct packed_git *p) fd_flag |= FD_CLOEXEC; if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1) return error("cannot set FD_CLOEXEC"); -#endif /* Verify we recognize this pack file format. */ if (read_in_full(p->pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) From 155e6d080b57b968f853b0076ea3de0f24f4975d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 17:44:08 +0100 Subject: [PATCH 0290/3720] Fix setitimer implementation to register only one cleanup with atexit. Signed-off-by: Johannes Sixt --- compat/mingw.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 63c632adaf..9b503a0eec 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -679,6 +679,7 @@ static inline int is_timeval_eq(const struct timeval *i1, const struct timeval * int setitimer(int type, struct itimerval *in, struct itimerval *out) { static const struct timeval zero; + static int atexit_done; if (out != NULL) return errno = EINVAL, @@ -697,7 +698,10 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out) timer_interval = in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000; one_shot = is_timeval_eq(&in->it_value, &zero); - atexit(stop_timer_thread); + if (!atexit_done) { + atexit(stop_timer_thread); + atexit_done = 1; + } return start_timer_thread(); } From a5ac001accd3566b910008cb5068802f7968b711 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 3 Nov 2007 22:35:03 +0100 Subject: [PATCH 0291/3720] upload-pack: rely on finish_command() and finish_async() We don't need explicitly handle the processes anymore. --- upload-pack.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 38b774fa34..34299308f8 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -265,29 +265,6 @@ static void create_pack_file(void) goto fail; } } - - if (finish_command(&pack_objects)) { - error("git-upload-pack: git-pack-objects died with error."); - goto fail; - } - if (finish_async(&rev_list)) - goto fail; /* error was already reported */ - - /* flush the data */ - if (0 <= buffered) { - data[0] = buffered; - sz = send_client_data(1, data, 1); - if (sz < 0) - goto fail; - fprintf(stderr, "flushed.\n"); - } - if (use_sideband) - packet_flush(1); - return; - - fail: - send_client_data(3, abort_msg, sizeof(abort_msg)); - die("git-upload-pack: %s", abort_msg); #else char *cp; @@ -322,6 +299,14 @@ static void create_pack_file(void) } else goto fail; +#endif + + if (finish_command(&pack_objects)) { + error("git-upload-pack: git-pack-objects died with error."); + goto fail; + } + if (finish_async(&rev_list)) + goto fail; /* error was already reported */ /* flush the data */ if (0 <= buffered) { @@ -333,16 +318,11 @@ static void create_pack_file(void) } if (use_sideband) packet_flush(1); - if (waitpid(pack_objects.pid, NULL, 0) < 0) - die("git-upload-pack: waiting for pack-objects: %s", - strerror(errno)); return; fail: - kill(pack_objects.pid, SIGKILL); send_client_data(3, abort_msg, sizeof(abort_msg)); die("git-upload-pack: %s", abort_msg); -#endif } static int got_sha1(char *hex, unsigned char *sha1) From fab21181f4b096a5f2b4f144353a0e22d35c5f7a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 15 Nov 2007 22:22:47 +0100 Subject: [PATCH 0292/3720] Implement a wrapper of the open() function. The wrapper does two things: - Requests to open /dev/null are redirected to open the nul pseudo file. - A request to open a file that currently exists as a directory, then Windows's open fails with EACCES; this is changed to EISDIR. Signed-off-by: Johannes Sixt --- compat/mingw.c | 20 ++++++++++++++++++++ git-compat-util.h | 5 ++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9b503a0eec..384b3b67a1 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,26 @@ unsigned int _CRT_fmode = _O_BINARY; +#undef open +int mingw_open (const char *filename, int oflags, ...) +{ + va_list args; + unsigned mode; + va_start(args, oflags); + mode = va_arg(args, int); + va_end(args); + + if (!strcmp(filename, "/dev/null")) + filename = "nul"; + int fd = open(filename, oflags, mode); + if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { + DWORD attrs = GetFileAttributes(filename); + if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) + errno = EISDIR; + } + return fd; +} + static inline time_t filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; diff --git a/git-compat-util.h b/git-compat-util.h index 1bbdb2f2fb..bfab97d057 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -500,9 +500,8 @@ static inline int git_unlink(const char *pathname) { } #define unlink git_unlink -#define open(P, F, M...) \ - (__builtin_constant_p(*(P)) && !strcmp(P, "/dev/null") ? \ - open("nul", F, ## M) : open(P, F, ## M)) +int mingw_open (const char *filename, int oflags, ...); +#define open mingw_open #include struct tm *gmtime_r(const time_t *timep, struct tm *result); From e8586bac156301508f66c0644d6614a003229e2c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 15 Nov 2007 22:26:49 +0100 Subject: [PATCH 0293/3720] Revert "Work around missing EISDIR errno values." This reverts the remaining part of commit ff61d9fc99a60a7c0320538a278d5f58680e120d. --- refs.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/refs.c b/refs.c index aa8045d89d..aff02cd09d 100644 --- a/refs.c +++ b/refs.c @@ -1059,15 +1059,6 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, if (!(oflags & O_CREAT) && errno == ENOENT) return 0; -#ifdef __MINGW32__ - if ((oflags & O_CREAT) && errno == EACCES) { - struct stat st; - if (stat(log_file, &st) == 0 && S_ISDIR(st.st_mode)) - errno = EISDIR; - else - errno = EACCES; - } -#endif if ((oflags & O_CREAT) && errno == EISDIR) { if (remove_empty_directories(log_file)) { return error("There are still logs under '%s'", From a8cf9a4ac19e9a2e01eb333144ef3bcef465a78b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 08:59:29 +0100 Subject: [PATCH 0294/3720] Remove unnecessary dd function. The test now uses test-genrandom instead of dd if=/dev/random. --- t/t5301-sliding-window.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/t/t5301-sliding-window.sh b/t/t5301-sliding-window.sh index 9a6d6aceac..073ac0c6f9 100755 --- a/t/t5301-sliding-window.sh +++ b/t/t5301-sliding-window.sh @@ -6,10 +6,6 @@ test_description='mmap sliding window tests' . ./test-lib.sh -dd () { - perl -e 'print pack("C", rand(256)) foreach 0 .. 32767' -} - test_expect_success \ 'setup' \ 'rm -f .git/index* From efe7309073bcb56b5de0d2f71cf02013c8a179fe Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 08:53:41 +0100 Subject: [PATCH 0295/3720] sum.exe is available from GNUWin32 (CoreUtils). --- t/t1002-read-tree-m-u-2way.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index 36642d4119..42e5cf8181 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -10,12 +10,6 @@ This is identical to t1001, but uses -u to update the work tree as well. ' . ./test-lib.sh -sum ./test-lib.sh >/dev/null 2>&1 || { - function sum () { - md5sum "$@" - } -} - _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { From 157737a3d92d067c09908a345ab595fb2b3d89bf Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 08:55:58 +0100 Subject: [PATCH 0296/3720] stat.exe is available from GNUWin32 (CoreUtils). --- t/t5300-pack-object.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 9a81d84106..169f60e33a 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -26,12 +26,6 @@ corrupt() ) < $1 > $2 } -test "$no_symlinks" && { - stat() { - ls -l "$3" | tr -s ' ' ' ' | cut -d' ' -f5 - } -} - test_expect_success \ 'setup' \ 'rm -f .git/index* From ff1c27fb4e28c253de43b6ca3e8ab00d594fb9c5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 08:58:13 +0100 Subject: [PATCH 0297/3720] Revert "Protect {tree} from being expanded by the shell." This reverts commit bff909b88259160b50823f277ea8c1426e4f7aa0. git-tag is now a builtin and does not need the extra escaping anymore. --- t/t5515-fetch-merge-logic.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 483a554d94..31c1081617 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -20,7 +20,7 @@ test_expect_success setup ' git add file && git commit -a -m One && git tag tag-one && - git-tag tag-one-tree HEAD^\{tree} && + git tag tag-one-tree HEAD^{tree} && git branch one && echo two >> file && @@ -31,7 +31,7 @@ test_expect_success setup ' echo three >> file && git commit -a -m Three && git tag -a -m "Tag Three" tag-three && - git-tag -a -m "Tag Three file" tag-three-file HEAD^\{tree}:file && + git tag -a -m "Tag Three file" tag-three-file HEAD^{tree}:file && git branch three && echo master >> file && From 3dffb74b2c118b1eb58aab27b7bbf76cee7974bb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 22:53:18 +0100 Subject: [PATCH 0298/3720] Use start_command() and finish_command() to run the pager. This gets rid of a call to spawnvpe_pipe() (and Windows-specific cwait()). --- pager.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/pager.c b/pager.c index a55f4e9d1e..de1bc799f5 100644 --- a/pager.c +++ b/pager.c @@ -1,5 +1,4 @@ #include "cache.h" -#include "spawn-pipe.h" /* * This is split up from the rest of git so that we might do @@ -23,12 +22,18 @@ static void run_pager(const char *pager) execl("/bin/sh", "sh", "-c", pager, NULL); } #else -static pid_t pager_pid; +#include "run-command.h" + +const char *pager_argv[] = { "sh", "-c", NULL, NULL }; +static struct child_process pager_process = { + .argv = pager_argv, + .in = -1 +}; static void collect_pager(void) { fflush(stdout); close(1); /* signals EOF to pager */ - cwait(NULL, pager_pid, 0); + finish_command(&pager_process); } #endif @@ -36,10 +41,8 @@ void setup_pager(void) { #ifndef __MINGW32__ pid_t pid; -#else - const char *pager_argv[] = { "sh", "-c", NULL, NULL }; -#endif int fd[2]; +#endif const char *pager = getenv("GIT_PAGER"); if (!isatty(1)) @@ -58,9 +61,9 @@ void setup_pager(void) pager_in_use = 1; /* means we are emitting to terminal */ +#ifndef __MINGW32__ if (pipe(fd) < 0) return; -#ifndef __MINGW32__ pid = fork(); if (pid < 0) { close(fd[0]); @@ -88,13 +91,12 @@ void setup_pager(void) #else /* spawn the pager */ pager_argv[2] = pager; - pager_pid = spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL); - if (pager_pid < 0) + if (start_command(&pager_process)) return; /* original process continues, but writes to the pipe */ - dup2(fd[1], 1); - close(fd[1]); + dup2(pager_process.in, 1); + close(pager_process.in); /* this makes sure that the parent terminates after the pager */ atexit(collect_pager); From 7828980b8c727d85e189400fbd21c59ddaa3c666 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 23:35:32 +0100 Subject: [PATCH 0299/3720] Revert "sum.exe is available from GNUWin32 (CoreUtils)." This reverts commit efe7309073bcb56b5de0d2f71cf02013c8a179fe. This "sum.exe" knows it better and writes CRLF line endings. Hmpf. --- t/t1002-read-tree-m-u-2way.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index 42e5cf8181..36642d4119 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -10,6 +10,12 @@ This is identical to t1001, but uses -u to update the work tree as well. ' . ./test-lib.sh +sum ./test-lib.sh >/dev/null 2>&1 || { + function sum () { + md5sum "$@" + } +} + _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { From 3deda759198c2a69f280135c0af67e51518cce51 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 17 Nov 2007 22:41:11 +0100 Subject: [PATCH 0300/3720] upload-pack: Do not announce sideband support when it is not supported On Windows we currently don't support sideband communicaton. The protocol implementation is already disabled, but it was still announced in the server capabilities. --- upload-pack.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 34299308f8..84569a3aad 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -596,8 +596,11 @@ static void receive_needs(void) static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - static const char *capabilities = "multi_ack thin-pack side-band" - " side-band-64k ofs-delta shallow no-progress"; + static const char *capabilities = "multi_ack thin-pack" +#ifndef __MINGW32__ + " side-band side-band-64k" +#endif + " ofs-delta shallow no-progress"; struct object *o = parse_object(sha1); if (!o) From 069930410211632f2f8beea303771088226b523f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 16:09:26 +0100 Subject: [PATCH 0301/3720] Use relative paths to make installation relocatable mingw uses relative paths for template_dir and ETC_GITCONFIG to make an installation relocatable. Relative paths will be expanded relative to git_exec_dir(). This mechanism is now included in official git.git. We used a different mechanism to create a relocatable installation. We used to prefix absolute Unix paths with the installation prefix, derived from the path of git.exe. This commit reverts our implementation to match mingw. Part of the change are reverts of the following commits, which are no longer needed: 4e8904080d62be07a139436aa44044e05e380a2c 0fbe22da392f39e1d144f78ef08b2dbdb882c164. 636116b8a79c7c810afe8ae8e4c37e0a1de6f7b7. Signed-off-by: Steffen Prohaska --- Makefile | 7 ++++--- builtin-init-db.c | 11 ----------- config.c | 11 ----------- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 4c749a0357..8586fcd397 100644 --- a/Makefile +++ b/Makefile @@ -523,7 +523,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) EXTLIBS += -lws2_32 X = .exe NOEXECTEMPL = .noexec - prefix = + template_dir = ../share/git-core/templates/ + ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease @@ -774,12 +775,12 @@ endif # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) -ETC_GITCONFIG_SQ = \057etc/gitconfig +ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) -template_dir_SQ = \057share/git-core/templates +template_dir_SQ = $(subst ','\'',$(template_dir)) prefix_SQ = $(subst ','\'',$(prefix)) sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) diff --git a/builtin-init-db.c b/builtin-init-db.c index 2feec40eb6..bb132ec086 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -145,17 +145,6 @@ static void copy_templates(const char *git_dir, int len, const char *template_di template_dir = prefix_path(exec_path, strlen(exec_path), template_dir); } -#if __MINGW32__ - /* - * If it is an absolute Unix path it is prefixed with - * the git_install_prefix(). - */ - else if (template_dir[0] == '/') { - const char* prefix = git_install_prefix(); - template_dir = prefix_path(prefix, strlen(prefix), - template_dir); - } -#endif } strcpy(template_path, template_dir); template_len = strlen(template_path); diff --git a/config.c b/config.c index 0b167ceb75..7b9ded1655 100644 --- a/config.c +++ b/config.c @@ -473,17 +473,6 @@ const char *git_etc_gitconfig(void) system_wide = prefix_path(exec_path, strlen(exec_path), system_wide); } -#if __MINGW32__ - /* - * If it is an absolute Unix path it is prefixed with - * the git_install_prefix(). - */ - else if (system_wide[0] == '/') { - const char* prefix = git_install_prefix(); - system_wide = prefix_path(prefix, strlen(prefix), - system_wide); - } -#endif } return system_wide; } From e9d8b9207e7ae7be0cf33a7cdc18d0e14c12c02a Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 16:43:13 +0100 Subject: [PATCH 0302/3720] help: search html documentation relativ to git_exec_dir() Global gitconfig and templates are searched relativ to git_exec_dir() to make the installation relocatable. This commit changes help to do the same for finding the html documentation. Signed-off-by: Steffen Prohaska --- help.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/help.c b/help.c index 90d5a03345..f89164a760 100644 --- a/help.c +++ b/help.c @@ -245,15 +245,16 @@ static void show_man_page(const char *git_cmd) { #ifdef __MINGW32__ { + const char* exec_path = git_exec_path(); char *htmlpath = make_native_separator( - mkpath("%s/doc/git/html/%s.html" - , git_install_prefix() - , git_cmd) + mkpath("%s/../doc/git/html/%s.html" + , exec_path + , git_cmd) ); if (!file_exists(htmlpath)) { htmlpath = make_native_separator( - mkpath("%s/doc/git/html/git-%s.html" - , git_install_prefix() + mkpath("%s/../doc/git/html/git-%s.html" + , exec_path , git_cmd) ); if (!file_exists(htmlpath)) { From 51355b1ede40a910bf4a62f9a8d0cbd7abcdecf7 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 16:45:19 +0100 Subject: [PATCH 0303/3720] remove git_install_prefix() git_install_prefix() is no longer needed. Relocatable paths are searched relative to git_exec_dir(). This commit removes git_install_prefix(). Signed-off-by: Steffen Prohaska --- cache.h | 1 - path.c | 35 ----------------------------------- 2 files changed, 36 deletions(-) diff --git a/cache.h b/cache.h index 1fbc9a1987..550e8ad192 100644 --- a/cache.h +++ b/cache.h @@ -391,7 +391,6 @@ static inline int is_dev_null(const char *str) const char *make_absolute_path(const char *path); /* Convert slashes in place. On Windows to backslashes. */ char *make_native_separator(char *path); -const char *git_install_prefix(); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/path.c b/path.c index 01f35d5e7d..2a76269705 100644 --- a/path.c +++ b/path.c @@ -359,41 +359,6 @@ const char *make_absolute_path(const char *path) return buf; } -const char* git_install_prefix() -{ -#ifdef __MINGW32__ - static char* prefix; - - if (prefix) { - return prefix; - } - - char* p; - int pgm_len = strlen(_pgmptr); - prefix = xmalloc(pgm_len + 1); - strcpy(prefix, _pgmptr); - p = strrchr(prefix, '\\'); /* \bin\ <- p */ - if (p) { - *p = '\0'; - p = strrchr(prefix, '\\'); /* \ <- p */ - if (p) { - *p = '\0'; - for (p = prefix; *p; p++) - if (*p == '\\') - *p = '/'; - return prefix; - } - } - - /* Note, according to the msdn documentation we have a full path - if started through the shell and this error should never happen. */ - fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); - exit(1); -#else - return ""; -#endif -} - char *make_native_separator(char* path) { #ifdef __MINGW32__ char* c; From 5e23af17e42294bae625713c754ad98838b5e9bc Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 22:40:12 +0100 Subject: [PATCH 0304/3720] Remove unnecessary decl of sync() Signed-off-by: Steffen Prohaska --- builtin-prune-packed.c | 2 -- builtin-prune.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index b61b73a900..23faf3129f 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -8,8 +8,6 @@ static const char prune_packed_usage[] = #define DRY_RUN 01 #define VERBOSE 02 -void sync(void); - static struct progress *progress; static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) diff --git a/builtin-prune.c b/builtin-prune.c index 02e4c09b0e..44df59e4a7 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -8,8 +8,6 @@ static const char prune_usage[] = "git-prune [-n]"; static int show_only; -void sync(void); - static int prune_object(char *path, const char *filename, const unsigned char *sha1) { if (show_only) { From 32dead9686779b65214c688bbe23eebdae2980f5 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 22:51:40 +0100 Subject: [PATCH 0305/3720] Use getpagesize() from git-compat-util.h Signed-off-by: Steffen Prohaska --- config.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/config.c b/config.c index 7b9ded1655..ed96213c44 100644 --- a/config.c +++ b/config.c @@ -15,8 +15,6 @@ static const char *config_file_name; static int config_linenr; static int zlib_compression_seen; -extern int getpagesize(); - static int get_next_char(void) { int c; From f8fd915d0c397c59ccf2f0cb96552e19b440dde8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:22:04 +0100 Subject: [PATCH 0306/3720] Move environment functions from spawn-pipe.c to compat/mingw.c We want to get rid of spawn-pipe.*, but these functions will be needed. On the way, the function signature was changed to avoid warnings about incompatible pointer types when the argument is the global variable "environ". --- compat/mingw.c | 39 +++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 4 ++++ spawn-pipe.c | 39 --------------------------------------- spawn-pipe.h | 3 --- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 384b3b67a1..0456319ba6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -536,6 +536,45 @@ void mingw_execvp(const char *cmd, const char **argv) mingw_free_path_split(path); } +char **copy_environ() +{ + return copy_env(environ); +} + +char **copy_env(char **env) +{ + char **s; + int n = 1; + for (s = env; *s; s++) + n++; + s = xmalloc(n*sizeof(char *)); + memcpy(s, env, n*sizeof(char *)); + return s; +} + +void env_unsetenv(char **env, const char *name) +{ + int src, dst; + size_t nmln; + + nmln = strlen(name); + + for (src = dst = 0; env[src]; ++src) { + size_t enln; + enln = strlen(env[src]); + if (enln > nmln) { + /* might match, and can test for '=' safely */ + if (0 == strncmp (env[src], name, nmln) + && '=' == env[src][nmln]) + /* matches, so skip */ + continue; + } + env[dst] = env[src]; + ++dst; + } + env[dst] = NULL; +} + int mingw_socket(int domain, int type, int protocol) { SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); diff --git a/git-compat-util.h b/git-compat-util.h index a259da5eeb..768e7fc696 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -473,6 +473,10 @@ static inline int waitpid(pid_t pid, unsigned *status, unsigned options) #define SIGCHLD 0 #define SIGPIPE 0 +char **copy_environ(); +char **copy_env(char **env); +void env_unsetenv(char **env, const char *name); + unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); diff --git a/spawn-pipe.c b/spawn-pipe.c index 71232066c5..9cb0cf5b70 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -129,42 +129,3 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, return pid; } - -const char **copy_environ() -{ - return copy_env(environ); -} - -const char **copy_env(const char **env) -{ - const char **s; - int n = 1; - for (s = env; *s; s++) - n++; - s = xmalloc(n*sizeof(const char *)); - memcpy(s, env, n*sizeof(const char *)); - return s; -} - -void env_unsetenv(const char **env, const char *name) -{ - int src, dst; - size_t nmln; - - nmln = strlen(name); - - for (src = dst = 0; env[src]; ++src) { - size_t enln; - enln = strlen(env[src]); - if (enln > nmln) { - /* might match, and can test for '=' safely */ - if (0 == strncmp (env[src], name, nmln) - && '=' == env[src][nmln]) - /* matches, so skip */ - continue; - } - env[dst] = env[src]; - ++dst; - } - env[dst] = NULL; -} diff --git a/spawn-pipe.h b/spawn-pipe.h index 3807819ae8..9bf387e411 100644 --- a/spawn-pipe.h +++ b/spawn-pipe.h @@ -1,5 +1,2 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); -const char **copy_environ(); -const char **copy_env(const char **env); -void env_unsetenv(const char **env, const char *name); From 3393222e4877c26a4d6ac8f43b7584efa4c571d3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:25:03 +0100 Subject: [PATCH 0307/3720] Reimplement start_command() to work just like the old spawnvpe_pipe(). The idea is to duplicate the handles that we want to pass to the child to stdin, stdout, or stderr after making a backup duplicate, then spawn the child program, then duplicate the backups back in place. --- run-command.c | 161 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 137 insertions(+), 24 deletions(-) diff --git a/run-command.c b/run-command.c index e5d029f7a2..05934f708f 100644 --- a/run-command.c +++ b/run-command.c @@ -1,7 +1,6 @@ #include "cache.h" #include "run-command.h" #include "exec_cmd.h" -#include "spawn-pipe.h" static inline void close_pair(int fd[2]) { @@ -9,13 +8,17 @@ static inline void close_pair(int fd[2]) close(fd[1]); } +static inline void dup_devnull(int to) +{ + int fd = open("/dev/null", O_RDWR); + dup2(fd, to); + close(fd); +} + int start_command(struct child_process *cmd) { int need_in, need_out, need_err; - int fdin[2] = { -1, -1 }; - int fdout[2] = { -1, -1 }; - int fderr[2] = { -1, -1 }; - char **env = environ; + int fdin[2], fdout[2], fderr[2]; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { @@ -50,53 +53,150 @@ int start_command(struct child_process *cmd) cmd->err = fderr[0]; } - { +#ifndef __MINGW32__ + cmd->pid = fork(); + if (!cmd->pid) { if (cmd->no_stdin) - fdin[0] = open("/dev/null", O_RDWR); + dup_devnull(0); else if (need_in) { - /* nothing */ + dup2(fdin[0], 0); + close_pair(fdin); } else if (cmd->in) { - fdin[0] = cmd->in; + dup2(cmd->in, 0); + close(cmd->in); } if (cmd->no_stdout) - fdout[1] = open("/dev/null", O_RDWR); + dup_devnull(1); else if (cmd->stdout_to_stderr) - fdout[1] = dup(2); + dup2(2, 1); else if (need_out) { - /* nothing */ + dup2(fdout[1], 1); + close_pair(fdout); } else if (cmd->out > 1) { - fdout[1] = cmd->out; + dup2(cmd->out, 1); + close(cmd->out); } if (cmd->no_stderr) - fderr[1] = open("/dev/null", O_RDWR); + dup_devnull(2); else if (need_err) { - /* nothing */ + dup2(fderr[1], 2); + close_pair(fderr); } - if (cmd->dir) - die("chdir in start_command() not implemented"); if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { - if (cmd->git_cmd) - die("modifying environment for git_cmd in start_command() not implemented"); - env = copy_environ(); for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - die("setting environment in start_command() not implemented"); + putenv((char*)*cmd->env); else - env_unsetenv(env, *cmd->env); + unsetenv(*cmd->env); } } if (cmd->git_cmd) { - cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout); + execv_git_cmd(cmd->argv); } else { - cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout); + execvp(cmd->argv[0], (char *const*) cmd->argv); + } + die("exec %s failed.", cmd->argv[0]); + } +#else + int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ + const char *sargv0 = cmd->argv[0]; + char **env = environ; + struct strbuf git_cmd; + + if (cmd->no_stdin) { + s0 = dup(0); + dup_devnull(0); + } else if (need_in) { + s0 = dup(0); + dup2(fdin[0], 0); + } else if (cmd->in) { + s0 = dup(0); + dup2(cmd->in, 0); + } + + if (cmd->no_stdout) { + s1 = dup(1); + dup_devnull(1); + } else if (cmd->stdout_to_stderr) { + s1 = dup(1); + dup2(2, 1); + } else if (need_out) { + s1 = dup(1); + dup2(fdout[1], 1); + } else if (cmd->out > 1) { + s1 = dup(1); + dup2(cmd->out, 1); + } + + if (cmd->no_stderr) { + s2 = dup(2); + dup_devnull(2); + } else if (need_err) { + s2 = dup(2); + dup2(fderr[1], 2); + } + + if (cmd->dir) + die("chdir in start_command() not implemented"); + if (cmd->env) { + env = copy_environ(); + for (; *cmd->env; cmd->env++) { + if (strchr(*cmd->env, '=')) + die("setting environment in start_command() not implemented"); + else + env_unsetenv(env, *cmd->env); } } + + if (cmd->git_cmd) { + strbuf_init(&git_cmd, 0); + strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]); + cmd->argv[0] = git_cmd.buf; + } + + char **path = mingw_get_path_split(); + const char *argv0 = cmd->argv[0]; + const char **qargv; + char *prog = mingw_path_lookup(argv0, path); + const char *interpr = parse_interpreter(prog); + int argc; + + for (argc = 0; cmd->argv[argc];) argc++; + qargv = xmalloc((argc+2)*sizeof(char*)); + if (!interpr) { + quote_argv(qargv, cmd->argv); + cmd->pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); + } else { + qargv[0] = interpr; + cmd->argv[0] = prog; + quote_argv(&qargv[1], cmd->argv); + cmd->pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); + } + + free(qargv); /* TODO: quoted args should be freed, too */ + free(prog); + + mingw_free_path_split(path); + /* TODO: if (cmd->env) free env; */ + + if (cmd->git_cmd) + strbuf_release(&git_cmd); + + cmd->argv[0] = sargv0; + if (s0 >= 0) + dup2(s0, 0), close(s0); + if (s1 >= 0) + dup2(s1, 1), close(s1); + if (s2 >= 0) + dup2(s2, 2), close(s2); +#endif + if (cmd->pid < 0) { if (need_in) close_pair(fdin); @@ -107,6 +207,19 @@ int start_command(struct child_process *cmd) return -ERR_RUN_COMMAND_FORK; } + if (need_in) + close(fdin[0]); + else if (cmd->in) + close(cmd->in); + + if (need_out) + close(fdout[1]); + else if (cmd->out > 1) + close(cmd->out); + + if (need_err) + close(fderr[1]); + return 0; } From 855cdbbc3b3bb8975687ddfbe63cd10bf44e1410 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:30:15 +0100 Subject: [PATCH 0308/3720] Remove now unused spawnv_git_cmd(). --- exec_cmd.c | 28 ---------------------------- exec_cmd.h | 1 - 2 files changed, 29 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 6aa842bb4f..9d22e78eb0 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,7 +1,6 @@ #include "cache.h" #include "exec_cmd.h" #include "quote.h" -#include "spawn-pipe.h" #define MAX_ARGS 32 extern char **environ; @@ -155,30 +154,3 @@ int execl_git_cmd(const char *cmd,...) argv[argc] = NULL; return execv_git_cmd(argv); } - -int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) -{ - pid_t pid; - struct strbuf cmd; - const char *tmp; - - strbuf_init(&cmd, 0); - strbuf_addf(&cmd, "git-%s", argv[0]); - - /* argv[0] must be the git command, but the argv array - * belongs to the caller. Save argv[0] and - * restore it later. - */ - - tmp = argv[0]; - argv[0] = cmd.buf; - - trace_argv_printf(argv, -1, "trace: exec:"); - - pid = spawnvpe_pipe(cmd.buf, argv, environ, - pin, pout); - - argv[0] = tmp; - return pid; - -} diff --git a/exec_cmd.h b/exec_cmd.h index 9e8a28489e..a892355c82 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -6,7 +6,6 @@ extern const char* git_exec_path(void); extern void setup_path(const char *); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); -extern int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]); #endif /* GIT_EXEC_CMD_H */ From d51703c66552023b930724fcdd9e6324b0f42f5e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:33:36 +0100 Subject: [PATCH 0309/3720] Remove now unused spawn-pipe.c with spawnvpe_pipe() function. --- Makefile | 2 - connect.c | 1 - spawn-pipe.c | 131 --------------------------------------------------- spawn-pipe.h | 2 - 4 files changed, 136 deletions(-) delete mode 100644 spawn-pipe.c delete mode 100644 spawn-pipe.h diff --git a/Makefile b/Makefile index e8058c3f19..7f5a2e4f4b 100644 --- a/Makefile +++ b/Makefile @@ -291,7 +291,6 @@ LIB_H = \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ - spawn-pipe.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h @@ -305,7 +304,6 @@ LIB_OBJS = \ date.o diff-delta.o entry.o exec_cmd.o ident.o \ pretty.o interpolate.o hash.o \ lockfile.o \ - spawn-pipe.o \ patch-ids.o \ object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \ sideband.o reachable.o reflog-walk.o \ diff --git a/connect.c b/connect.c index e11cf32321..0f10c40652 100644 --- a/connect.c +++ b/connect.c @@ -5,7 +5,6 @@ #include "refs.h" #include "run-command.h" #include "remote.h" -#include "spawn-pipe.h" static char *server_capabilities; diff --git a/spawn-pipe.c b/spawn-pipe.c deleted file mode 100644 index 9cb0cf5b70..0000000000 --- a/spawn-pipe.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "git-compat-util.h" -#include "spawn-pipe.h" - -extern char **environ; - -/* cmd specifies the command to invoke. - * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. - * env specifies the environment. - * pin and pout specify pipes; the read end of pin is made the standard input - * of the spawned process, and the write end of pout is mad the standard output. - * The respective unused ends of the pipes are closed both in the parent - * process as well as in the child process. - * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to - * indicate that no processing shall occur. - */ -int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, - int pin[], int pout[]) -{ -#ifdef __MINGW32__ - char **path = mingw_get_path_split(); - - pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); - - mingw_free_path_split(path); -#else - pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout); -#endif - return pid; -} - -int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, - char **path, - int pin[], int pout[]) -{ - const char *cmd_basename = strrchr(cmd, '/'); - const char *argv0 = argv[0]; - pid_t pid; - -#ifdef __MINGW32__ - int s0 = -1, s1 = -1, argc; - char *prog; - const char **qargv, *interpr; - - if (!cmd_basename) - cmd_basename = strrchr(cmd, '\\'); -#endif - - if (!cmd_basename) - cmd_basename = cmd; - else - cmd_basename++; - argv[0] = cmd_basename; - -#ifndef __MINGW32__ - pid = fork(); - if (pid < 0) - die("unable to fork"); - if (!pid) { - if (pin) { - if (pin[0] >= 0) { - dup2(pin[0], 0); - close(pin[0]); - } - if (pin[1] >= 0) - close(pin[1]); - } - if (pout) { - if (pout[1] >= 0) { - dup2(pout[1], 1); - close(pout[1]); - } - if (pout[0] >= 0) - close(pout[0]); - } - environ = env; - execvp(cmd, argv); - die("exec failed"); - } - - if (pin && pin[0] >= 0) - close(pin[0]); - if (pout && pout[1] >= 1) - close(pout[1]); -#else - if (pin) { - if (pin[0] >= 0) { - s0 = dup(0); - dup2(pin[0], 0); - close(pin[0]); - } - } - if (pout) { - if (pout[1] >= 0) { - s1 = dup(1); - dup2(pout[1], 1); - close(pout[1]); - } - } - - prog = mingw_path_lookup(cmd, path); - interpr = parse_interpreter(prog); - - for (argc = 0; argv[argc];) argc++; - qargv = xmalloc((argc+2)*sizeof(char*)); - if (!interpr) { - quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, env); - } else { - qargv[0] = interpr; - argv[0] = prog; - quote_argv(&qargv[1], argv); - pid = spawnvpe(_P_NOWAIT, interpr, qargv, env); - } - - free(qargv); /* TODO: quoted args should be freed, too */ - free(prog); - - if (s0 >= 0) { - dup2(s0, 0); - close(s0); - } - if (s1 >= 0) { - dup2(s1, 1); - close(s1); - } -#endif - - argv[0] = argv0; - - return pid; -} diff --git a/spawn-pipe.h b/spawn-pipe.h deleted file mode 100644 index 9bf387e411..0000000000 --- a/spawn-pipe.h +++ /dev/null @@ -1,2 +0,0 @@ -int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); -int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); From 8ddaf895a80c1d42bd0e923cb0f1f041d00a27ea Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:27:40 +0100 Subject: [PATCH 0310/3720] compat/mingw.c: Add cast of handle to fix warning [js: whitespace removed] Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0456319ba6..b18231e903 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -235,7 +235,7 @@ int pipe(int filedes[2]) CloseHandle(h[0]); return -1; } - fd = _open_osfhandle(h[0], O_NOINHERIT); + fd = _open_osfhandle((int)h[0], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); @@ -245,7 +245,7 @@ int pipe(int filedes[2]) } close(filedes[0]); filedes[0] = fd; - fd = _open_osfhandle(h[1], O_NOINHERIT); + fd = _open_osfhandle((int)h[1], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); From f593be04806654aaff987f660e1998b0e19a9b8b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:43:30 +0100 Subject: [PATCH 0311/3720] test-chmtime.c: Cast HANDLE to fix warning Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- test-chmtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-chmtime.c b/test-chmtime.c index b6dc548a2a..8a1e6b8479 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -22,7 +22,7 @@ int git_utime (const char *file_name, const struct utimbuf *times) time_t_to_filetime(times->modtime, &mft); time_t_to_filetime(times->actime, &aft); - if (!SetFileTime(_get_osfhandle(fh), NULL, &aft, &mft)) { + if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { errno = EINVAL; rc = -1; } else From a8d8425ec6f2b75c59562b6e9a7508ab623a2cd4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 21:07:32 +0100 Subject: [PATCH 0312/3720] Fix prototypes for mingw_execve and mingw_execvp to match Posix This changes the prototypes to match http://www.opengroup.org/onlinepubs/7990989775/xsh/exec.html [js: updated message] Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- compat/mingw.c | 19 ++++++++++--------- git-compat-util.h | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index b18231e903..ad44c86a98 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -352,7 +352,7 @@ static const char *quote_arg(const char *arg) return q; } -void quote_argv(const char **dst, const char **src) +void quote_argv(const char **dst, const char *const *src) { while (*src) *dst++ = quote_arg(*src++); @@ -394,7 +394,7 @@ const char *parse_interpreter(const char *cmd) return p+1; } -static int try_shell_exec(const char *cmd, const char **argv, const char **env) +static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) { const char **sh_argv; int n; @@ -412,14 +412,14 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) sh_argv = xmalloc((n+2)*sizeof(char*)); sh_argv[0] = interpr; sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], &argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, env); + quote_argv(&sh_argv[2], (const char *const *)&argv[1]); + n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); if (n == -1) return 1; /* indicate that we tried but failed */ exit(n); } -void mingw_execve(const char *cmd, const char **argv, const char **env) +void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { @@ -427,8 +427,9 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) int n; for (n = 0; argv[n];) n++; qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, argv); - int ret = spawnve(_P_WAIT, cmd, qargv, env); + quote_argv(qargv, (const char *const *)argv); + int ret = spawnve(_P_WAIT, cmd, qargv, + (const char *const *)env); if (ret != -1) exit(ret); } @@ -522,13 +523,13 @@ void mingw_free_path_split(char **path) free(path); } -void mingw_execvp(const char *cmd, const char **argv) +void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); char *prog = mingw_path_lookup(cmd, path); if (prog) { - mingw_execve(prog, argv, (const char **) environ); + mingw_execve(prog, argv, environ); free(prog); } else errno = ENOENT; diff --git a/git-compat-util.h b/git-compat-util.h index 768e7fc696..c88186d685 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -451,9 +451,9 @@ static inline int kill(pid_t pid, int sig) static inline unsigned int alarm(unsigned int seconds) { return 0; } -void mingw_execve(const char *cmd, const char **argv, const char **env); +void mingw_execve(const char *cmd, char *const *argv, char * const *env); #define execve mingw_execve -extern void mingw_execvp(const char *cmd, const char **argv); +extern void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp typedef int pid_t; static inline int waitpid(pid_t pid, unsigned *status, unsigned options) @@ -527,7 +527,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} extern int getpagesize(void); /* defined in MinGW's libgcc.a */ -extern void quote_argv(const char **dst, const char **src); +extern void quote_argv(const char **dst, const char *const *src); extern const char *parse_interpreter(const char *cmd); extern char *mingw_path_lookup(const char *cmd, char **path); extern char **mingw_get_path_split(void); From f801325ed5fd9d3f4732dbef18f4270c4ea89654 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 19 Nov 2007 12:34:22 +0100 Subject: [PATCH 0313/3720] Implement a rudimentary poll() emulation for Windows. This emulation of poll() is by far not general. It assumes that the fds that are to be waited for are connected to pipes. The pipes are polled in a loop until data becomes available in at least one of them. If only a single fd is waited for, the implementation actually does not wait at all, but assumes that a subsequent read() will block. In order to not burn CPU time, it is yielded to other processes before the next round in the poll loop using Sleep(0). Note that any sleep timeout greater than zero will reduce the efficiency by a magnitude. Signed-off-by: Johannes Sixt --- compat/mingw.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ad44c86a98..676aae573e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -259,7 +259,62 @@ int pipe(int filedes[2]) int poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - return -1; + int i, pending; + + if (timeout != -1) + return errno = EINVAL, error("poll timeout not supported"); + + /* When there is only one fd to wait for, then we pretend that + * input is available and let the actual wait happen when the + * caller invokes read(). + */ + if (nfds == 1) { + if (!(ufds[0].events & POLLIN)) + return errno = EINVAL, error("POLLIN not set"); + ufds[0].revents = POLLIN; + return 0; + } + +repeat: + pending = 0; + for (i = 0; i < nfds; i++) { + DWORD avail = 0; + HANDLE h = (HANDLE) _get_osfhandle(ufds[i].fd); + if (h == INVALID_HANDLE_VALUE) + return -1; /* errno was set */ + + if (!(ufds[i].events & POLLIN)) + return errno = EINVAL, error("POLLIN not set"); + + /* this emulation works only for pipes */ + if (!PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL)) { + int err = GetLastError(); + if (err == ERROR_BROKEN_PIPE) { + ufds[i].revents = POLLHUP; + pending++; + } else { + errno = EINVAL; + return error("PeekNamedPipe failed," + " GetLastError: %u", err); + } + } else if (avail) { + ufds[i].revents = POLLIN; + pending++; + } else + ufds[i].revents = 0; + } + if (!pending) { + /* The only times that we spin here is when the process + * that is connected through the pipes is waiting for + * its own input data to become available. But since + * the process (pack-objects) is itself CPU intensive, + * it will happily pick up the time slice that we are + * relinguishing here. + */ + Sleep(0); + goto repeat; + } + return 0; } #include From 40c18e8ee6fcb5128719ee6e1b5aabee689da436 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 19 Nov 2007 12:39:57 +0100 Subject: [PATCH 0314/3720] upload-pack: Remove MinGW specific code. Now that a poll() implementation is available, upload-pack also offers side-band communication. --- upload-pack.c | 45 ++------------------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 84569a3aad..75e2acb29e 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -174,7 +174,6 @@ static void create_pack_file(void) if (start_command(&pack_objects)) die("git-upload-pack: unable to fork git-pack-objects"); -#ifndef __MINGW32__ /* We read from pack_objects.err to capture stderr output for * progress bar, and pack_objects.out to capture the pack data. */ @@ -265,41 +264,6 @@ static void create_pack_file(void) goto fail; } } -#else - char *cp; - - /* We read from pack_objects.out to capture the pack data. */ - - while ((sz = xread(pack_objects.out, data+1, sizeof(data)-1)) > 0) { - cp = data+1; - /* Data ready; we keep the last byte to ourselves in case we - * detect broken rev-list, so that we can leave the stream - * corrupted. This is unfortunate -- unpack-objects would - * happily accept a valid pack data with trailing garbage, so - * appending garbage after we pass all the pack data is not - * good enough to signal breakage to downstream. - */ - if (0 <= buffered) { - *--cp = buffered; - sz++; - } - if (1 < sz) { - buffered = cp[sz-1] & 0xFF; - sz--; - } - else - buffered = -1; - sz = send_client_data(1, cp, sz); - if (sz < 0) - goto fail; - } - if (sz == 0) { - close(pack_objects.out); - pack_objects.out = -1; - } - else - goto fail; -#endif if (finish_command(&pack_objects)) { error("git-upload-pack: git-pack-objects died with error."); @@ -521,12 +485,10 @@ static void receive_needs(void) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) use_ofs_delta = 1; -#ifndef __MINGW32__ if (strstr(line+45, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (strstr(line+45, "side-band")) use_sideband = DEFAULT_PACKET_MAX; -#endif if (strstr(line+45, "no-progress")) no_progress = 1; @@ -596,11 +558,8 @@ static void receive_needs(void) static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - static const char *capabilities = "multi_ack thin-pack" -#ifndef __MINGW32__ - " side-band side-band-64k" -#endif - " ofs-delta shallow no-progress"; + static const char *capabilities = "multi_ack thin-pack side-band" + " side-band-64k ofs-delta shallow no-progress"; struct object *o = parse_object(sha1); if (!o) From ad0b9993f9e21199cca77c0f04770e4013090d26 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Sat, 17 Nov 2007 20:32:08 +0100 Subject: [PATCH 0315/3720] compat/regex.c: Fix warnings In general, we don't add unnecessary braces. But in this case gcc warns about them. So this commit adds a few braces. The commit suppresses warnings about unitialized variables by initializing them to NULL. The change of bcmp_translate()'s parameter declaration is needed to avoid warnings about "discards qualifiers from pointer target type". [sp: split original commit; more detailed commit message. ] Signed-off-by: Dmitry Kakurin Signed-off-by: Steffen Prohaska --- compat/regex.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compat/regex.c b/compat/regex.c index 2d57c70b9c..1d39e08d47 100644 --- a/compat/regex.c +++ b/compat/regex.c @@ -1597,10 +1597,12 @@ regex_compile (pattern, size, syntax, bufp) if (syntax & RE_NO_BK_PARENS) goto normal_backslash; if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_backslash; else return REG_ERPAREN; + } handle_close: if (fixup_alt_jump) @@ -1617,10 +1619,12 @@ regex_compile (pattern, size, syntax, bufp) /* See similar code for backslashed left paren above. */ if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_char; else return REG_ERPAREN; + } /* Since we just checked for an empty stack above, this ``can't happen''. */ @@ -3191,14 +3195,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matching and the regnum-th regend points to right after where we stopped matching the regnum-th subexpression. (The zeroth register keeps track of what the whole pattern matches.) */ - const char **regstart, **regend; + const char **regstart = NULL, **regend = NULL; /* If a group that's operated upon by a repetition operator fails to match anything, then the register for its start will need to be restored because it will have been set to wherever in the string we are when we last see its open-group operator. Similarly for a register's end. */ - const char **old_regstart, **old_regend; + const char **old_regstart = NULL, **old_regend = NULL; /* The is_active field of reg_info helps us keep track of which (possibly nested) subexpressions we are currently in. The matched_something @@ -3206,14 +3210,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matched any of the pattern so far this time through the reg_num-th subexpression. These two fields get reset each time through any loop their register is in. */ - register_info_type *reg_info; + register_info_type *reg_info = NULL; /* The following record the register info as found in the above variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = false; - const char **best_regstart, **best_regend; + const char **best_regstart = NULL, **best_regend = NULL; /* Logically, this is `best_regend[0]'. But we don't want to have to allocate space for that if we're not allocating space for anything @@ -3226,8 +3230,8 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) const char *match_end = NULL; /* Used when we pop values we don't care about. */ - const char **reg_dummy; - register_info_type *reg_info_dummy; + const char **reg_dummy = NULL; + register_info_type *reg_info_dummy = NULL; #ifdef DEBUG /* Counts the total number of registers pushed. */ @@ -4561,10 +4565,12 @@ common_op_match_null_string_p (p, end, reg_info) bytes; nonzero otherwise. */ static int -bcmp_translate (s1, s2, len, translate) - unsigned char *s1, *s2; - register int len; - char *translate; +bcmp_translate( + unsigned char *s1, + unsigned char *s2, + int len, + char *translate +) { register unsigned char *p1 = s1, *p2 = s2; while (len) From 5a09d6a3ac8f4fa39e059ad61ece1aabd5a861e1 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:48:14 +0100 Subject: [PATCH 0316/3720] compat/pread.c: Add foward decl to fix warning read_in_full()'s is used in compat/pread.c. read_in_full() is declared in cache.h. But we can't include cache.h because too many macros are defined there. Using read_in_full() without including cache.h is dangerous because we wouldn't recognize if its prototyp changed. gcc issues a warning about that. This commit adds a forward decl to git-compat-util.h. git-compat-util.h is included by compat/pread.c _and_ cache.h. Hence, changes in cache.h would be detected. Signed-off-by: Steffen Prohaska --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index c88186d685..b76f94fc05 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -153,6 +153,10 @@ extern int git_munmap(void *start, size_t length); #define pread git_pread extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif +/* Forward decl that will remind us if its twin in cache.h changes. + This function in used in compat/pread.c. But we can't include + cache.h there. */ +extern int read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv From c2849fc4b1a4618f2d81ef2597d7e40d7b2e048c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:16:53 +0100 Subject: [PATCH 0317/3720] Fix ntohl() related warnings about printf formatting On Windows, ntohl() returns unsinged long. On Unix it returns uint32_t. This makes choosing a suitable printf format string hard. This commit introduces a mingw specific helper function git_ntohl() that casts to unsigned int before returning. This makes gcc's printf format check happy. It should be safe because we expect ntohl to use 32-bit numbers. Signed-off-by: Steffen Prohaska --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index b76f94fc05..74412331d8 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -594,6 +594,10 @@ static inline int mingw_fcntl(int fd, int cmd, long arg) { return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } #define fcntl mingw_fcntl +static inline unsigned int git_ntohl(unsigned int x) +{ return (unsigned int)ntohl(x); } +#define ntohl git_ntohl + #endif /* __MINGW32__ */ #endif From a6ed49cf52589d26235dc2461ebaf8b38446b061 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Nov 2007 09:21:12 +0100 Subject: [PATCH 0318/3720] Fix error messages in timer implementation. There were some references to the progress indicator, where this implementation originally appeared. Signed-off-by: Johannes Sixt --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 676aae573e..aa730e9bc1 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -760,10 +760,10 @@ static int start_timer_thread(void) timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL); if (!timer_thread ) return errno = ENOMEM, - error("cannot create progress indicator"); + error("cannot start timer thread"); } else return errno = ENOMEM, - error("cannot allocate resources for progress indicator"); + error("cannot allocate resources timer"); return 0; } From 726fb5ed5ded96f6a60a7adf41e50b6c00b4f246 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 17 Nov 2007 22:42:12 +0100 Subject: [PATCH 0319/3720] fetch-pack: Enable sideband communication. --- builtin-fetch-pack.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 2f37b5cd24..807fa93b53 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -563,7 +563,6 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports multi_ack\n"); multi_ack = 1; } -#ifndef __MINGW32__ if (server_supports("side-band-64k")) { if (args.verbose) fprintf(stderr, "Server supports side-band-64k\n"); @@ -574,7 +573,6 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports side-band\n"); use_sideband = 1; } -#endif if (!ref) { packet_flush(fd[1]); die("no matching remote head"); From 66417d164e18193aef3bd935ab6e7755f5161f73 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 22:00:39 +0100 Subject: [PATCH 0320/3720] Add ifdef __MINGW32__ to avoid warning about unused "progress" Signed-off-by: Steffen Prohaska --- upload-pack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/upload-pack.c b/upload-pack.c index 97ffa879f3..115f7a1e56 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -143,6 +143,9 @@ static void create_pack_file(void) struct child_process pack_objects; int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); char data[8193]; +#ifndef __MINGW32__ + char progress[128]; +#endif char abort_msg[] = "aborting due to possible repository " "corruption on the remote side."; int buffered = -1; From af18e7d9d3abad0e42477a3c15c0e3f0bdc9ae15 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 21:07:32 +0100 Subject: [PATCH 0321/3720] Fix prototypes for mingw_execve and mingw_execvp to match Posix This changes the prototypes to match http://www.opengroup.org/onlinepubs/7990989775/xsh/exec.html Note, spawnvpe uses a different type for argv and envp than execve. So at some point we need to cast. This commit shifts the cast into the compat functions. From the outside, execve and execvp match Posix. Signed-off-by: Steffen Prohaska --- compat/mingw.c | 19 ++++++++++--------- git-compat-util.h | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index b905673a40..b841f6d0ca 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -352,7 +352,7 @@ static const char *quote_arg(const char *arg) return q; } -void quote_argv(const char **dst, const char **src) +void quote_argv(const char **dst, const char *const *src) { while (*src) *dst++ = quote_arg(*src++); @@ -394,7 +394,7 @@ const char *parse_interpreter(const char *cmd) return p+1; } -static int try_shell_exec(const char *cmd, const char **argv, const char **env) +static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) { const char **sh_argv; int n; @@ -412,14 +412,14 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) sh_argv = xmalloc((n+2)*sizeof(char*)); sh_argv[0] = interpr; sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], &argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, env); + quote_argv(&sh_argv[2], (const char *const *)&argv[1]); + n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); if (n == -1) return 1; /* indicate that we tried but failed */ exit(n); } -void mingw_execve(const char *cmd, const char **argv, const char **env) +void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { @@ -427,8 +427,9 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) int n; for (n = 0; argv[n];) n++; qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, argv); - int ret = spawnve(_P_WAIT, cmd, qargv, env); + quote_argv(qargv, (const char *const *)argv); + int ret = spawnve(_P_WAIT, cmd, qargv, + (const char *const *)env); if (ret != -1) exit(ret); } @@ -522,13 +523,13 @@ void mingw_free_path_split(char **path) free(path); } -void mingw_execvp(const char *cmd, const char **argv) +void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); char *prog = mingw_path_lookup(cmd, path); if (prog) { - mingw_execve(prog, argv, (const char **) environ); + mingw_execve(prog, argv, environ); free(prog); } else errno = ENOENT; diff --git a/git-compat-util.h b/git-compat-util.h index 921a6c08b4..eb4d96944e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -454,9 +454,9 @@ static inline int kill(pid_t pid, int sig) static inline unsigned int alarm(unsigned int seconds) { return 0; } -void mingw_execve(const char *cmd, const char **argv, const char **env); +void mingw_execve(const char *cmd, char *const *argv, char * const *env); #define execve mingw_execve -extern void mingw_execvp(const char *cmd, const char **argv); +extern void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp typedef int pid_t; static inline int waitpid(pid_t pid, unsigned *status, unsigned options) @@ -526,7 +526,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} extern int getpagesize(void); /* defined in MinGW's libgcc.a */ -extern void quote_argv(const char **dst, const char **src); +extern void quote_argv(const char **dst, const char *const *src); extern const char *parse_interpreter(const char *cmd); extern char *mingw_path_lookup(const char *cmd, char **path); extern char **mingw_get_path_split(void); From ad941f23363d2f37cef8dd6a59b61be2b740997c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 22:43:26 +0100 Subject: [PATCH 0322/3720] exec_cmd.c: Add cast that is needed for Posix execvp Signed-off-by: Steffen Prohaska --- exec_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec_cmd.c b/exec_cmd.c index a2d82d3311..de4c174b68 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -121,7 +121,7 @@ int execv_git_cmd(const char **argv) trace_argv_printf(argv, -1, "trace: exec:"); /* execvp() can only ever return if it fails */ - execvp(cmd.buf, argv); + execvp(cmd.buf, (char **)argv); trace_printf("trace: exec failed: %s\n", strerror(errno)); From 565861de3b6357339fdcd087fa52fc4c14b6de24 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 23:01:56 +0100 Subject: [PATCH 0323/3720] spawn-pipe.c: Remove unnecessary cast Signed-off-by: Steffen Prohaska --- spawn-pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spawn-pipe.c b/spawn-pipe.c index 04146d5631..e685eff643 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -103,7 +103,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, qargv = xmalloc((argc+2)*sizeof(char*)); if (!interpr) { quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, (const char**) env); + pid = spawnve(_P_NOWAIT, prog, qargv, env); } else { qargv[0] = interpr; argv[0] = prog; From d3dcd107758907e38751fb50631e9acf315a6bad Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Nov 2007 12:23:52 +0100 Subject: [PATCH 0324/3720] git.c: Take '--bare' handling from mingw master Merge commit 53009e47c2b55d6c23925bb77116545f2308cef9 introduced an if() statement that is not present in mingw's master. This commit changes the code to match mingw's master. Signed-off-by: Steffen Prohaska --- git.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/git.c b/git.c index 615093453b..e2c79a1efc 100644 --- a/git.c +++ b/git.c @@ -72,11 +72,9 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) } else if (!strcmp(cmd, "--bare")) { static char git_dir[PATH_MAX+1]; is_bare_repository_cfg = 1; - if (!getenv(GIT_DIR_ENVIRONMENT)) { - set_git_dir(getcwd(git_dir, sizeof(git_dir))); - if (envchanged) - *envchanged = 1; - } + set_git_dir(getcwd(git_dir, sizeof(git_dir))); + if (envchanged) + *envchanged = 1; } else { fprintf(stderr, "Unknown option: %s\n", cmd); usage(git_usage_string); From 31023be9997d657dc653fe3358be50d1e7268a31 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:48:14 +0100 Subject: [PATCH 0325/3720] compat/pread.c: Add foward decl to fix warning read_in_full()'s is used in compat/pread.c. read_in_full() is declared in cache.h. But we can't include cache.h because too many macros are defined there. Using read_in_full() without including cache.h is dangerous because we wouldn't recognize if its prototyp changed. gcc issues a warning about that. This commit adds a forward decl to git-compat-util.h. git-compat-util.h is included by compat/pread.c _and_ cache.h. Hence, changes in cache.h would be detected. Signed-off-by: Steffen Prohaska --- compat/pread.c | 2 -- git-compat-util.h | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compat/pread.c b/compat/pread.c index ce29997724..978cac4ec9 100644 --- a/compat/pread.c +++ b/compat/pread.c @@ -1,7 +1,5 @@ #include "../git-compat-util.h" -int read_in_full(int fd, void *buf, size_t count); - ssize_t git_pread(int fd, void *buf, size_t count, off_t offset) { off_t current_offset; diff --git a/git-compat-util.h b/git-compat-util.h index eb4d96944e..f4e0d08357 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -153,6 +153,10 @@ extern int git_munmap(void *start, size_t length); #define pread git_pread extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif +/* Forward decl that will remind us if its twin in cache.h changes. + This function in used in compat/pread.c. But we can't include + cache.h there. */ +extern int read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv From 43664aa169b6efeb80245772f7ad9ff1c6e5edb0 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:16:53 +0100 Subject: [PATCH 0326/3720] Revert ntohl()/printf format to Junio's git This commits reverts printf format strings to the original version from Juion's git. This is a preparation for the mingw specific fix that follows in the next commit. Signed-off-by: Steffen Prohaska --- builtin-fetch-pack.c | 2 +- builtin-ls-files.c | 2 +- builtin-unpack-objects.c | 2 +- index-pack.c | 2 +- merge-index.c | 2 +- read-cache.c | 2 +- receive-pack.c | 2 +- sha1_file.c | 4 ++-- show-index.c | 2 +- unpack-trees.c | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 3510bfd089..a2ca746dd0 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -509,7 +509,7 @@ static int get_pack(int xd[2], char **pack_lockfile) if (read_pack_header(fd[0], &header)) die("protocol error: bad pack header"); - snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%lu,%lu", + snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", ntohl(header.hdr_version), ntohl(header.hdr_entries)); if (ntohl(header.hdr_entries) < unpack_limit) do_keep = 0; diff --git a/builtin-ls-files.c b/builtin-ls-files.c index dde79545e2..e0b856f432 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -208,7 +208,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) if (!show_stage) { fputs(tag, stdout); } else { - printf("%s%06lo %s %d\t", + printf("%s%06o %s %d\t", tag, ntohl(ce->ce_mode), abbrev ? find_unique_abbrev(ce->sha1,abbrev) diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 948e4bec51..1e51865c52 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -318,7 +318,7 @@ static void unpack_all(void) if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE) die("bad pack file"); if (!pack_version_ok(hdr->hdr_version)) - die("unknown pack file version %lu", ntohl(hdr->hdr_version)); + die("unknown pack file version %d", ntohl(hdr->hdr_version)); use(sizeof(struct pack_header)); if (!quiet) diff --git a/index-pack.c b/index-pack.c index 6268da94b8..9fd6982a97 100644 --- a/index-pack.c +++ b/index-pack.c @@ -143,7 +143,7 @@ static void parse_pack_header(void) if (hdr->hdr_signature != htonl(PACK_SIGNATURE)) die("pack signature mismatch"); if (!pack_version_ok(hdr->hdr_version)) - die("pack version %lu unsupported", ntohl(hdr->hdr_version)); + die("pack version %d unsupported", ntohl(hdr->hdr_version)); nr_objects = ntohl(hdr->hdr_entries); use(sizeof(struct pack_header)); diff --git a/merge-index.c b/merge-index.c index 1cf4cb5b3f..fa719cb0b1 100644 --- a/merge-index.c +++ b/merge-index.c @@ -48,7 +48,7 @@ static int merge_entry(int pos, const char *path) break; found++; strcpy(hexbuf[stage], sha1_to_hex(ce->sha1)); - sprintf(ownbuf[stage], "%lo", ntohl(ce->ce_mode)); + sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode)); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; } while (++pos < active_nr); diff --git a/read-cache.c b/read-cache.c index 128835b684..7748c3ece7 100644 --- a/read-cache.c +++ b/read-cache.c @@ -152,7 +152,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) case 0: /* Special case: unmerged file in index */ return MODE_CHANGED | DATA_CHANGED | TYPE_CHANGED; default: - die("internal error: ce_mode is %lo", ntohl(ce->ce_mode)); + die("internal error: ce_mode is %o", ntohl(ce->ce_mode)); } if (ce->ce_mtime.sec != htonl(st->st_mtime)) changed |= MTIME_CHANGED; diff --git a/receive-pack.c b/receive-pack.c index a66a6e45d2..38e35c06b9 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -352,7 +352,7 @@ static const char *unpack(void) hdr_err = parse_pack_header(&hdr); if (hdr_err) return hdr_err; - snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%lu,%lu", + snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { diff --git a/sha1_file.c b/sha1_file.c index 6b0e4c1d02..bd0e7cd21c 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -670,13 +670,13 @@ static int open_packed_git_1(struct packed_git *p) if (hdr.hdr_signature != htonl(PACK_SIGNATURE)) return error("file %s is not a GIT packfile", p->pack_name); if (!pack_version_ok(hdr.hdr_version)) - return error("packfile %s is version %lu and not supported" + return error("packfile %s is version %u and not supported" " (try upgrading GIT to a newer version)", p->pack_name, ntohl(hdr.hdr_version)); /* Verify the pack matches its index. */ if (p->num_objects != ntohl(hdr.hdr_entries)) - return error("packfile %s claims to have %lu objects" + return error("packfile %s claims to have %u objects" " while index indicates %u objects", p->pack_name, ntohl(hdr.hdr_entries), p->num_objects); diff --git a/show-index.c b/show-index.c index 9749e2da48..7253991fff 100644 --- a/show-index.c +++ b/show-index.c @@ -68,7 +68,7 @@ int main(int argc, char **argv) ntohl(off64[1]); off64_nr++; } - printf("%" PRIuMAX " %s (%08lx)\n", (uintmax_t) offset, + printf("%" PRIuMAX " %s (%08x)\n", (uintmax_t) offset, sha1_to_hex(entries[i].sha1), ntohl(entries[i].crc)); } diff --git a/unpack-trees.c b/unpack-trees.c index 18f586cefc..aea16adde8 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -638,7 +638,7 @@ static void show_stage_entry(FILE *o, if (!ce) fprintf(o, "%s (missing)\n", label); else - fprintf(o, "%s%06lo %s %d\t%s\n", + fprintf(o, "%s%06o %s %d\t%s\n", label, ntohl(ce->ce_mode), sha1_to_hex(ce->sha1), From 329bdf025be694c6944c63550af1cd30b84612ab Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:16:53 +0100 Subject: [PATCH 0327/3720] Fix ntohl() related warnings about printf formatting On Windows, ntohl() returns unsinged long. On Unix it returns uint32_t. This makes choosing a suitable printf format string hard. This commit introduces a mingw specific helper function git_ntohl() that casts to unsigned int before returning. This makes gcc's printf format check happy. It should be safe because we expect ntohl to use 32-bit numbers. Signed-off-by: Steffen Prohaska --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index f4e0d08357..42564918de 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -593,6 +593,10 @@ static inline int mingw_fcntl(int fd, int cmd, long arg) { return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } #define fcntl mingw_fcntl +static inline unsigned int git_ntohl(unsigned int x) +{ return (unsigned int)ntohl(x); } +#define ntohl git_ntohl + extern __attribute__((noreturn)) int git_exit(int code); #define exit git_exit From 60db5000ab3307def85fd8e4618e661a565c1750 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Nov 2007 22:47:00 +0100 Subject: [PATCH 0328/3720] Implement wrappers for gethostbyname(), socket(), and connect(). gethostbyname() is the first function that calls into the Winsock library, and it is wrapped only to initialize the library. socket() is wrapped for two reasons: - Windows's socket() creates things that are like low-level file handles, and they must be converted into file descriptors first. - And these handles cannot be used with plain ReadFile()/WriteFile() because they are opened for "overlapped IO". We have to use WSASocket() to create non-overlapped IO sockets. connect() must be wrapped because Windows's connect() expects the low-level sockets, not file descriptors, and we must first unwrap the file descriptor before we can pass it on to Windows's connect(). Signed-off-by: Johannes Sixt --- compat/mingw.c | 29 ++++++++++++++++++++++++++++- git-compat-util.h | 6 ++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index aa730e9bc1..f2d18a7410 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -631,8 +631,22 @@ void env_unsetenv(char **env, const char *name) env[dst] = NULL; } +/* this is the first function to call into WS_32; initialize it */ +#undef gethostbyname +struct hostent *mingw_gethostbyname(const char *host) +{ + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2,2), &wsa)) + die("unable to initialize winsock subsystem, error %d", + WSAGetLastError()); + atexit((void(*)(void)) WSACleanup); + return gethostbyname(host); +} + int mingw_socket(int domain, int type, int protocol) { + int sockfd; SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); if (s == INVALID_SOCKET) { /* @@ -647,7 +661,20 @@ int mingw_socket(int domain, int type, int protocol) errno = WSAGetLastError(); return -1; } - return s; + /* convert into a file descriptor */ + if ((sockfd = _open_osfhandle(s, O_RDWR|O_BINARY)) < 0) { + closesocket(s); + return error("unable to make a socket file descriptor: %s", + strerror(errno)); + } + return sockfd; +} + +#undef connect +int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) +{ + SOCKET s = (SOCKET)_get_osfhandle(sockfd); + return connect(s, sa, sz); } #undef rename diff --git a/git-compat-util.h b/git-compat-util.h index 74412331d8..1d147af906 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -520,9 +520,15 @@ struct tm *localtime_r(const time_t *timep, struct tm *result); char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd +struct hostent *mingw_gethostbyname(const char *host); +#define gethostbyname mingw_gethostbyname + int mingw_socket(int domain, int type, int protocol); #define socket mingw_socket +int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); +#define connect mingw_connect + int mingw_rename(const char*, const char*); #define rename mingw_rename From d0d5661addd02d3aca9e543457f962eacae704a2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Nov 2007 22:48:07 +0100 Subject: [PATCH 0329/3720] Revert Windows specific code related to Winsock. These things are now hidden behind a compatibility layer. --- connect.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/connect.c b/connect.c index 0f10c40652..82fb62b080 100644 --- a/connect.c +++ b/connect.c @@ -345,23 +345,7 @@ static int git_tcp_connect_sock(char *host, int flags) static void git_tcp_connect(int fd[2], char *host, int flags) { -#ifndef __MINGW32__ int sockfd = git_tcp_connect_sock(host, flags); -#else - int sockfd; - WSADATA wsa; - - if (WSAStartup(MAKEWORD(2,2), &wsa)) - die("unable to initialize winsock subsystem, error %d", - WSAGetLastError()); - atexit((void(*)(void)) WSACleanup); - - sockfd = git_tcp_connect_sock(host, flags); - /* convert into a file descriptor */ - if ((sockfd = _open_osfhandle(sockfd, O_RDWR|O_BINARY)) < 0) - die("unable to make a socket file descriptor: %s", - strerror(errno)); -#endif fd[0] = sockfd; fd[1] = dup(sockfd); From 9c906c8e6c49b0bfa66580a35bcf013ee122970c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 22 Nov 2007 22:24:56 +0100 Subject: [PATCH 0330/3720] Be more careful in splitting the program name from the path. A git program can be invoked using with such a full path name: C:\Src\mingw-git\t\trash/..\..\git-fetch-pack.exe i.e. it can contain both types of path separators. We must pick the one that comes last. Signed-off-by: Johannes Sixt --- git.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git.c b/git.c index e5fdd04057..04ef05fcf5 100644 --- a/git.c +++ b/git.c @@ -399,8 +399,9 @@ int main(int argc, const char **argv) * if we don't have anything better. */ #ifdef __MINGW32__ - if (!slash) - slash = strrchr(cmd, '\\'); + char *bslash = strrchr(cmd, '\\'); + if (!slash || (bslash && bslash > slash)) + slash = bslash; #endif if (slash) { *slash++ = 0; From 64529de34e408212bcb5e0b44573ddc2081bf84c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 24 Nov 2007 11:53:06 +0100 Subject: [PATCH 0331/3720] Enable some disabled tests, remove workarounds msysgit learnt to handle more tests. This commit enables some tests that were disabled before and reverts some workarounds that are no longer needed. Signed-off-by: Steffen Prohaska --- t/t3200-branch.sh | 1 - t/t3404-rebase-interactive.sh | 8 ++++---- t/t3900-i18n-commit.sh | 4 ---- t/t4121-apply-diffs.sh | 2 -- t/t5100-mailinfo.sh | 4 ---- t/t5302-pack-index.sh | 2 -- t/t6023-merge-file.sh | 3 --- t/t6200-fmt-merge-msg.sh | 1 - t/t7003-filter-branch.sh | 3 --- t/t7004-tag.sh | 4 ++-- t/t9300-fast-import.sh | 4 ---- 11 files changed, 6 insertions(+), 30 deletions(-) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 029f19d6fa..a891fa47d3 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -17,7 +17,6 @@ test_expect_success \ git-commit -m "Initial commit." && HEAD=$(git rev-parse --verify HEAD)' -true || test_expect_failure \ 'git branch --help should not have created a bogus branch' \ 'git branch --help /dev/null 2>/dev/null || : diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index c031d31698..f1039d1a21 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -164,7 +164,7 @@ test_expect_success 'retain authorship' ' test_tick && GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && git tag twerp && - git rebase -i --onto master HEAD~1 && + git rebase -i --onto master HEAD^ && git show HEAD | grep "^Author: Twerp Snog" ' @@ -208,7 +208,7 @@ test_expect_success 'preserve merges with -p' ' test_expect_success '--continue tries to commit' ' test_tick && - ! git rebase -i --onto new-branch1 HEAD~1 && + ! git rebase -i --onto new-branch1 HEAD^ && echo resolved > file1 && git add file1 && FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue && @@ -217,9 +217,9 @@ test_expect_success '--continue tries to commit' ' ' test_expect_success 'verbose flag is heeded, even after --continue' ' - git reset --hard $(git rev-parse HEAD@{1}) && + git reset --hard HEAD@{1} && test_tick && - ! git rebase -v -i --onto new-branch1 HEAD~1 && + ! git rebase -v -i --onto new-branch1 HEAD^ && echo resolved > file1 && git add file1 && git rebase --continue > output && diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 12812f924a..94b1c24b0a 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -7,10 +7,6 @@ test_description='commit and log output encodings' . ./test-lib.sh -say "iconv not supported, skipping tests." -test_done -exit 0 - compare_with () { git show -s $1 | sed -e '1,/^$/d' -e 's/^ //' >current && git diff current "$2" diff --git a/t/t4121-apply-diffs.sh b/t/t4121-apply-diffs.sh index d93b61d8c4..aff551a1d7 100755 --- a/t/t4121-apply-diffs.sh +++ b/t/t4121-apply-diffs.sh @@ -3,8 +3,6 @@ test_description='git apply for contextually independent diffs' . ./test-lib.sh -test_done - echo '1 2 3 diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 0dcab1fbfe..9b1a74542a 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -7,10 +7,6 @@ test_description='git mailinfo and git mailsplit test' . ./test-lib.sh -say "git-mailinfo does not work yet; skipping tests." -test_done -exit 0 - test_expect_success 'split sample box' \ 'git mailsplit -o. ../t5100/sample.mbox >last && last=`cat last` && diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 8f62429306..2a2878b572 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -59,7 +59,6 @@ test_expect_success \ 'cmp "test-1-${pack1}.idx" "1.idx" && cmp "test-2-${pack2}.idx" "2.idx"' -false && { test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 merge.err && grep "Cannot merge binary files" merge.err diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 878f51a8d9..526d7d1c44 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -9,7 +9,6 @@ test_description='fmt-merge-msg test' datestamp=1151939923 setdate () { - sleep 1 GIT_COMMITTER_DATE="$datestamp +0200" GIT_AUTHOR_DATE="$datestamp +0200" datestamp=`expr "$datestamp" + 1` diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index ed467c7009..2089351f7d 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -3,9 +3,6 @@ test_description='git-filter-branch' . ./test-lib.sh -say "filter-branch has not been taken care of - skipping tests" -test_done - make_commit () { lower=$(echo $1 | tr A-Z a-z) echo $lower > $lower diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 42d4e42dec..b9ac9e3eb3 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -116,9 +116,9 @@ mytag EOF test_expect_success \ 'trying to delete tags without params should succeed and do nothing' ' - git tag -l | cat > actual && git diff expect actual && + git tag -l > actual && git diff expect actual && git-tag -d && - git tag -l | cat > actual && git diff expect actual + git tag -l > actual && git diff expect actual ' test_expect_success \ diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index d92bf36f9c..0595041af5 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -7,10 +7,6 @@ test_description='test git-fast-import utility' . ./test-lib.sh . ../diff-lib.sh ;# test-lib chdir's into trash -say "git-fast-import has not been taken care of, skipping test." -test_done -exit 0 - file2_data='file2 second line of EOF' From 68c35c48f0db379e8138ba21b294ad04c3ca8b3b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 24 Nov 2007 20:04:30 +0100 Subject: [PATCH 0332/3720] Disable test of output of failing git-upload-pack More work is needed in mingw before the output of git-upload-pack is identical to the output on Unix. This commit disables verification of the output. Signed-off-by: Steffen Prohaska --- t/t5530-upload-pack-error.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh index cc8949e3ef..014064a3bd 100755 --- a/t/t5530-upload-pack-error.sh +++ b/t/t5530-upload-pack-error.sh @@ -55,6 +55,7 @@ test_expect_success 'upload-pack fails due to error in rev-list' ' ! echo "0032want $(git rev-parse HEAD) 00000009done 0000" | git-upload-pack . > /dev/null 2> output.err && + true || grep "waitpid (async) failed" output.err ' From ec848b1965f29eda62f389bfcd653540fe58ca12 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 24 Nov 2007 22:53:20 +0100 Subject: [PATCH 0333/3720] Shuffle path lookup functions. We want to make them static later, and we need them in the proper order for this. There is otherwise no code change. Signed-off-by: Johannes Sixt --- compat/mingw.c | 158 ++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f2d18a7410..850ee2ad5c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -449,85 +449,6 @@ const char *parse_interpreter(const char *cmd) return p+1; } -static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) -{ - const char **sh_argv; - int n; - const char *interpr = parse_interpreter(cmd); - if (!interpr) - return 0; - - /* - * expand - * git-foo args... - * into - * sh git-foo args... - */ - for (n = 0; argv[n];) n++; - sh_argv = xmalloc((n+2)*sizeof(char*)); - sh_argv[0] = interpr; - sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], (const char *const *)&argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); - if (n == -1) - return 1; /* indicate that we tried but failed */ - exit(n); -} - -void mingw_execve(const char *cmd, char *const *argv, char *const *env) -{ - /* check if git_command is a shell script */ - if (!try_shell_exec(cmd, argv, env)) { - const char **qargv; - int n; - for (n = 0; argv[n];) n++; - qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, (const char *const *)argv); - int ret = spawnve(_P_WAIT, cmd, qargv, - (const char *const *)env); - if (ret != -1) - exit(ret); - } -} - -static char *lookup_prog(const char *dir, const char *cmd, int tryexe) -{ - char path[MAX_PATH]; - snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); - - if (tryexe && access(path, 0) == 0) - return xstrdup(path); - path[strlen(path)-4] = '\0'; - if (access(path, 0) == 0) - return xstrdup(path); - return NULL; -} - -/* - * Determines the absolute path of cmd using the the split path in path. - * If cmd contains a slash or backslash, no lookup is performed. - */ -char *mingw_path_lookup(const char *cmd, char **path) -{ - char **p = path; - char *prog = NULL; - int len = strlen(cmd); - int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); - - if (strchr(cmd, '/') || strchr(cmd, '\\')) - prog = xstrdup(cmd); - - while (!prog && *p) { - prog = lookup_prog(*p++, cmd, tryexe); - } - if (!prog) { - prog = lookup_prog(".", cmd, tryexe); - if (!prog) - prog = xstrdup(cmd); - } - return prog; -} - /* * Splits the PATH into parts. */ @@ -578,6 +499,85 @@ void mingw_free_path_split(char **path) free(path); } +static char *lookup_prog(const char *dir, const char *cmd, int tryexe) +{ + char path[MAX_PATH]; + snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); + + if (tryexe && access(path, 0) == 0) + return xstrdup(path); + path[strlen(path)-4] = '\0'; + if (access(path, 0) == 0) + return xstrdup(path); + return NULL; +} + +/* + * Determines the absolute path of cmd using the the split path in path. + * If cmd contains a slash or backslash, no lookup is performed. + */ +char *mingw_path_lookup(const char *cmd, char **path) +{ + char **p = path; + char *prog = NULL; + int len = strlen(cmd); + int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); + + if (strchr(cmd, '/') || strchr(cmd, '\\')) + prog = xstrdup(cmd); + + while (!prog && *p) { + prog = lookup_prog(*p++, cmd, tryexe); + } + if (!prog) { + prog = lookup_prog(".", cmd, tryexe); + if (!prog) + prog = xstrdup(cmd); + } + return prog; +} + +static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) +{ + const char **sh_argv; + int n; + const char *interpr = parse_interpreter(cmd); + if (!interpr) + return 0; + + /* + * expand + * git-foo args... + * into + * sh git-foo args... + */ + for (n = 0; argv[n];) n++; + sh_argv = xmalloc((n+2)*sizeof(char*)); + sh_argv[0] = interpr; + sh_argv[1] = quote_arg(cmd); + quote_argv(&sh_argv[2], (const char *const *)&argv[1]); + n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); + if (n == -1) + return 1; /* indicate that we tried but failed */ + exit(n); +} + +void mingw_execve(const char *cmd, char *const *argv, char *const *env) +{ + /* check if git_command is a shell script */ + if (!try_shell_exec(cmd, argv, env)) { + const char **qargv; + int n; + for (n = 0; argv[n];) n++; + qargv = xmalloc((n+1)*sizeof(char*)); + quote_argv(qargv, (const char *const *)argv); + int ret = spawnve(_P_WAIT, cmd, qargv, + (const char *const *)env); + if (ret != -1) + exit(ret); + } +} + void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); From 424e2045aa0b07071780fa0a97c75962b779256e Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 25 Nov 2007 17:48:17 +0100 Subject: [PATCH 0334/3720] help (mingw): Avoid current working directory when displaying html help We should specify a working directory to ShellExecute for the following reason. ShellExecute uses the current working directory if not told otherwise. html.c did not override this default. Therefore the current working directory was in use as long as the browser displaying the HTML help was open. As long as a directory is in use, it can't be deleted. This commit changes help.c to avoid this problem. The HTML browser is launched in the root directory "\\". Signed-off-by: Steffen Prohaska --- help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help.c b/help.c index f89164a760..a9ec6a77e7 100644 --- a/help.c +++ b/help.c @@ -264,7 +264,7 @@ static void show_man_page(const char *git_cmd) } } printf("Launching default browser to display HTML help ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); + ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } #else const char *page; From a020210cc8edd757b6e0f6d2ac1ba767f9d662ed Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 24 Nov 2007 21:32:48 +0100 Subject: [PATCH 0335/3720] Move MinGW specific path lookup into compat/mingw.c. By doing so the only external user of the path handling and functions is removed, and these functions can be made static. Signed-off-by: Johannes Sixt --- compat/mingw.c | 41 +++++++++++++++++++++++++++++++++++------ git-compat-util.h | 11 ++--------- run-command.c | 23 +---------------------- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 850ee2ad5c..6d2e518256 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -407,14 +407,14 @@ static const char *quote_arg(const char *arg) return q; } -void quote_argv(const char **dst, const char *const *src) +static void quote_argv(const char **dst, const char *const *src) { while (*src) *dst++ = quote_arg(*src++); *dst = NULL; } -const char *parse_interpreter(const char *cmd) +static const char *parse_interpreter(const char *cmd) { static char buf[100]; char *p, *opt; @@ -452,7 +452,7 @@ const char *parse_interpreter(const char *cmd) /* * Splits the PATH into parts. */ -char **mingw_get_path_split(void) +static char **mingw_get_path_split(void) { char *p, **path, *envpath = getenv("PATH"); int i, n = 0; @@ -488,7 +488,7 @@ char **mingw_get_path_split(void) return path; } -void mingw_free_path_split(char **path) +static void mingw_free_path_split(char **path) { if (!path) return; @@ -516,7 +516,7 @@ static char *lookup_prog(const char *dir, const char *cmd, int tryexe) * Determines the absolute path of cmd using the the split path in path. * If cmd contains a slash or backslash, no lookup is performed. */ -char *mingw_path_lookup(const char *cmd, char **path) +static char *mingw_path_lookup(const char *cmd, char **path) { char **p = path; char *prog = NULL; @@ -537,6 +537,35 @@ char *mingw_path_lookup(const char *cmd, char **path) return prog; } +pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) +{ + pid_t pid; + char **path = mingw_get_path_split(); + const char **qargv; + char *prog = mingw_path_lookup(cmd, path); + const char *interpr = parse_interpreter(prog); + int argc; + + for (argc = 0; argv[argc];) argc++; + qargv = xmalloc((argc+2)*sizeof(char*)); + if (!interpr) { + quote_argv(qargv, argv); + pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); + } else { + qargv[0] = interpr; + qargv[1] = quote_arg(prog); + quote_argv(&qargv[2], &argv[1]); + pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); + } + + free(qargv); /* TODO: quoted args should be freed, too */ + free(prog); + + mingw_free_path_split(path); + + return pid; +} + static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) { const char **sh_argv; @@ -562,7 +591,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) exit(n); } -void mingw_execve(const char *cmd, char *const *argv, char *const *env) +static void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { diff --git a/git-compat-util.h b/git-compat-util.h index 31d43152d2..5235d31f27 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -470,11 +470,10 @@ static inline int kill(pid_t pid, int sig) static inline unsigned int alarm(unsigned int seconds) { return 0; } -void mingw_execve(const char *cmd, char *const *argv, char * const *env); -#define execve mingw_execve +typedef int pid_t; +extern pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); extern void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp -typedef int pid_t; static inline int waitpid(pid_t pid, unsigned *status, unsigned options) { if (options == 0) @@ -552,12 +551,6 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} extern int getpagesize(void); /* defined in MinGW's libgcc.a */ -extern void quote_argv(const char **dst, const char *const *src); -extern const char *parse_interpreter(const char *cmd); -extern char *mingw_path_lookup(const char *cmd, char **path); -extern char **mingw_get_path_split(void); -extern void mingw_free_path_split(char **path); - /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. * struct stat is redefined because it lacks the st_blocks member. diff --git a/run-command.c b/run-command.c index 05934f708f..cf1377de64 100644 --- a/run-command.c +++ b/run-command.c @@ -160,29 +160,8 @@ int start_command(struct child_process *cmd) cmd->argv[0] = git_cmd.buf; } - char **path = mingw_get_path_split(); - const char *argv0 = cmd->argv[0]; - const char **qargv; - char *prog = mingw_path_lookup(argv0, path); - const char *interpr = parse_interpreter(prog); - int argc; + cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); - for (argc = 0; cmd->argv[argc];) argc++; - qargv = xmalloc((argc+2)*sizeof(char*)); - if (!interpr) { - quote_argv(qargv, cmd->argv); - cmd->pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); - } else { - qargv[0] = interpr; - cmd->argv[0] = prog; - quote_argv(&qargv[1], cmd->argv); - cmd->pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); - } - - free(qargv); /* TODO: quoted args should be freed, too */ - free(prog); - - mingw_free_path_split(path); /* TODO: if (cmd->env) free env; */ if (cmd->git_cmd) From 72d58fde995f38454069a9be80a747f0f1a844cc Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 24 Nov 2007 22:49:16 +0100 Subject: [PATCH 0336/3720] Implement a custom spawnve() on Windows. The problem with Windows's own implementation is that it tries to be clever when a console program is invoked from a GUI application: In this case it sometimes automatically allocates a new console windows. As a consequence, the IO channels of the spawned program are directed to the console, but the invoking application listens on channels that are now directed to nowhere. In this implementation we use the lowlevel facilities of CreateProcess(), which offers a flag to tell the system not to open a console. As a side effect, only stdin, stdout, and stderr channels will be accessible from C programs that are spawned. Other channels (file handles, pipe handles, etc.) are still inherited by the spawned program, but it doesn't get enough information to access them. Johannes Schindelin integrated path quoting and unified the various *execv* and *spawnv* helpers. Signed-off-by: Johannes Sixt --- compat/mingw.c | 215 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 161 insertions(+), 54 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6d2e518256..432e56ccd5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,5 +1,6 @@ #include #include "../git-compat-util.h" +#include "../strbuf.h" unsigned int _CRT_fmode = _O_BINARY; @@ -351,7 +352,10 @@ void openlog(const char *ident, int option, int facility) { } -/* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx (Parsing C++ Command-Line Arguments */ +/* + * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx + * (Parsing C++ Command-Line Arguments) + */ static const char *quote_arg(const char *arg) { /* count chars to quote */ @@ -407,13 +411,6 @@ static const char *quote_arg(const char *arg) return q; } -static void quote_argv(const char **dst, const char *const *src) -{ - while (*src) - *dst++ = quote_arg(*src++); - *dst = NULL; -} - static const char *parse_interpreter(const char *cmd) { static char buf[100]; @@ -537,73 +534,183 @@ static char *mingw_path_lookup(const char *cmd, char **path) return prog; } +static int env_compare(const void *a, const void *b) +{ + char *const *ea = a; + char *const *eb = b; + return strcasecmp(*ea, *eb); +} + +static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, + int prepend_cmd) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + struct strbuf envblk, args; + unsigned flags; + BOOL ret; + + /* Determine whether or not we are associated to a console */ + HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE, + FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (cons == INVALID_HANDLE_VALUE) { + /* There is no console associated with this process. + * Since the child is a console process, Windows + * would normally create a console window. But + * since we'll be redirecting std streams, we do + * not need the console. + */ + flags = CREATE_NO_WINDOW; + } else { + /* There is already a console. If we specified + * CREATE_NO_WINDOW here, too, Windows would + * disassociate the child from the console. + * Go figure! + */ + flags = 0; + CloseHandle(cons); + } + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = (HANDLE) _get_osfhandle(0); + si.hStdOutput = (HANDLE) _get_osfhandle(1); + si.hStdError = (HANDLE) _get_osfhandle(2); + + /* concatenate argv, quoting args as we go */ + strbuf_init(&args, 0); + if (prepend_cmd) { + char *quoted = (char *)quote_arg(cmd); + strbuf_addstr(&args, quoted); + if (quoted != cmd) + free(quoted); + } + for (; *argv; argv++) { + char *quoted = (char *)quote_arg(*argv); + if (*args.buf) + strbuf_addch(&args, ' '); + strbuf_addstr(&args, quoted); + if (quoted != *argv) + free(quoted); + } + + if (env) { + int count = 0; + char **e, **sorted_env; + + for (e = env; *e; e++) + count++; + + /* environment must be sorted */ + sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1)); + memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1)); + qsort(sorted_env, count, sizeof(*sorted_env), env_compare); + + strbuf_init(&envblk, 0); + for (e = sorted_env; *e; e++) { + strbuf_addstr(&envblk, *e); + strbuf_addch(&envblk, '\0'); + } + free(sorted_env); + } + + memset(&pi, 0, sizeof(pi)); + ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags, + env ? envblk.buf : NULL, NULL, &si, &pi); + + if (env) + strbuf_release(&envblk); + strbuf_release(&args); + + if (!ret) { + errno = ENOENT; + return -1; + } + CloseHandle(pi.hThread); + return (pid_t)pi.hProcess; +} + pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) { pid_t pid; char **path = mingw_get_path_split(); - const char **qargv; char *prog = mingw_path_lookup(cmd, path); - const char *interpr = parse_interpreter(prog); - int argc; - for (argc = 0; argv[argc];) argc++; - qargv = xmalloc((argc+2)*sizeof(char*)); - if (!interpr) { - quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); - } else { - qargv[0] = interpr; - qargv[1] = quote_arg(prog); - quote_argv(&qargv[2], &argv[1]); - pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); + if (!prog) { + errno = ENOENT; + pid = -1; } + else { + const char *interpr = parse_interpreter(prog); - free(qargv); /* TODO: quoted args should be freed, too */ - free(prog); - + if (interpr) { + const char *argv0 = argv[0]; + char *iprog = mingw_path_lookup(interpr, path); + argv[0] = prog; + if (!iprog) { + errno = ENOENT; + pid = -1; + } + else { + pid = mingw_spawnve(iprog, argv, env, 1); + free(iprog); + } + argv[0] = argv0; + } + else + pid = mingw_spawnve(prog, argv, env, 0); + free(prog); + } mingw_free_path_split(path); - return pid; } -static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) +static int try_shell_exec(const char *cmd, char *const *argv, char **env) { - const char **sh_argv; - int n; const char *interpr = parse_interpreter(cmd); + char **path; + char *prog; + int pid = 0; + if (!interpr) return 0; - - /* - * expand - * git-foo args... - * into - * sh git-foo args... - */ - for (n = 0; argv[n];) n++; - sh_argv = xmalloc((n+2)*sizeof(char*)); - sh_argv[0] = interpr; - sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], (const char *const *)&argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); - if (n == -1) - return 1; /* indicate that we tried but failed */ - exit(n); + path = mingw_get_path_split(); + prog = mingw_path_lookup(interpr, path); + if (prog) { + int argc = 0; + const char **argv2; + while (argv[argc]) argc++; + argv2 = xmalloc(sizeof(*argv) * (argc+1)); + argv2[0] = (char *)cmd; /* full path to the script file */ + memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc); + pid = mingw_spawnve(prog, argv2, env, 1); + if (pid >= 0) { + int status; + if (waitpid(pid, &status, 0) < 0) + status = 255; + exit(status); + } + pid = 1; /* indicate that we tried but failed */ + free(prog); + free(argv2); + } + mingw_free_path_split(path); + return pid; } static void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ - if (!try_shell_exec(cmd, argv, env)) { - const char **qargv; - int n; - for (n = 0; argv[n];) n++; - qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, (const char *const *)argv); - int ret = spawnve(_P_WAIT, cmd, qargv, - (const char *const *)env); - if (ret != -1) - exit(ret); + if (!try_shell_exec(cmd, argv, (char **)env)) { + int pid, status; + + pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0); + if (pid < 0) + return; + if (waitpid(pid, &status, 0) < 0) + status = 255; + exit(status); } } From 3920a6b76b8be1a405d5e30c69e3d0ba63ce5a5d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 23 Nov 2007 23:23:39 +0100 Subject: [PATCH 0337/3720] Look up interpreters only as .exe files. After a program was determined to be a script (which implies that it did not have a file extension), then the interpreter is looked up. This change makes sure that we will only find .exe files when we are looking for an interpreter. Otherwise, we could find a directory 'perl' that is somewhere earlier in the path than 'perl.exe'. Signed-off-by: Johannes Sixt --- compat/mingw.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 432e56ccd5..a25063b7f7 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -496,15 +496,19 @@ static void mingw_free_path_split(char **path) free(path); } -static char *lookup_prog(const char *dir, const char *cmd, int tryexe) +/* + * exe_only means that we only want to detect .exe files, but not scripts + * (which do not have an extension) + */ +static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only) { char path[MAX_PATH]; snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); - if (tryexe && access(path, 0) == 0) + if (!isexe && access(path, F_OK) == 0) return xstrdup(path); path[strlen(path)-4] = '\0'; - if (access(path, 0) == 0) + if ((!exe_only || isexe) && access(path, F_OK) == 0) return xstrdup(path); return NULL; } @@ -513,21 +517,21 @@ static char *lookup_prog(const char *dir, const char *cmd, int tryexe) * Determines the absolute path of cmd using the the split path in path. * If cmd contains a slash or backslash, no lookup is performed. */ -static char *mingw_path_lookup(const char *cmd, char **path) +static char *mingw_path_lookup(const char *cmd, char **path, int exe_only) { char **p = path; char *prog = NULL; int len = strlen(cmd); - int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); + int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe"); if (strchr(cmd, '/') || strchr(cmd, '\\')) prog = xstrdup(cmd); while (!prog && *p) { - prog = lookup_prog(*p++, cmd, tryexe); + prog = lookup_prog(*p++, cmd, isexe, exe_only); } if (!prog) { - prog = lookup_prog(".", cmd, tryexe); + prog = lookup_prog(".", cmd, isexe, exe_only); if (!prog) prog = xstrdup(cmd); } @@ -635,7 +639,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) { pid_t pid; char **path = mingw_get_path_split(); - char *prog = mingw_path_lookup(cmd, path); + char *prog = mingw_path_lookup(cmd, path, 0); if (!prog) { errno = ENOENT; @@ -646,7 +650,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) if (interpr) { const char *argv0 = argv[0]; - char *iprog = mingw_path_lookup(interpr, path); + char *iprog = mingw_path_lookup(interpr, path, 1); argv[0] = prog; if (!iprog) { errno = ENOENT; @@ -676,7 +680,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env) if (!interpr) return 0; path = mingw_get_path_split(); - prog = mingw_path_lookup(interpr, path); + prog = mingw_path_lookup(interpr, path, 1); if (prog) { int argc = 0; const char **argv2; @@ -717,7 +721,7 @@ static void mingw_execve(const char *cmd, char *const *argv, char *const *env) void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); - char *prog = mingw_path_lookup(cmd, path); + char *prog = mingw_path_lookup(cmd, path, 0); if (prog) { mingw_execve(prog, argv, environ); From bfe13b635738de33368a5ce297a981438dfc955b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 26 Nov 2007 13:14:34 +0100 Subject: [PATCH 0338/3720] Fix setitimer implementation. Although we made sure that in->it_interval is either zero or equal to in->it_value, we were still using in->it_interval to compute the timeout, which could be zero, for example, with git-log's --early-output flag. Use in->it_value instead. On the otherhand, we used in->it_value to check for a single-shot timer. Use in->it_interval instead. Signed-off-by: Johannes Sixt --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index a25063b7f7..e57c74e0ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -978,8 +978,8 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out) is_timeval_eq(&in->it_interval, &zero)) return 0; - timer_interval = in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000; - one_shot = is_timeval_eq(&in->it_value, &zero); + timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000; + one_shot = is_timeval_eq(&in->it_interval, &zero); if (!atexit_done) { atexit(stop_timer_thread); atexit_done = 1; From 79fba817db0dad5f4c4bd3982b20d5d7f5accd9d Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:10:18 +0100 Subject: [PATCH 0339/3720] sha1_file.c: Fix size_t related printf format warnings The old way of fixing warnings did not succeed on MinGW. MinGW does not support C99 printf format strings for size_t [1]. But gcc on MinGW issues warnings if C99 printf format is not used. Hence, the old stragegy to avoid warnings fails. [1] http://www.mingw.org/MinGWiki/index.php/C99 This commits passes arguments of type size_t through a tiny helper functions that casts to the type expected by the format string. Signed-off-by: Steffen Prohaska --- sha1_file.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index bd0e7cd21c..1984e35823 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -25,8 +25,10 @@ #ifdef NO_C99_FORMAT #define SZ_FMT "lu" +static unsigned long sz_fmt(size_t s) { return (unsigned long)s; } #else #define SZ_FMT "zu" +static size_t sz_fmt(size_t s) { return s; } #endif const unsigned char null_sha1[20]; @@ -431,9 +433,9 @@ void pack_report(void) "pack_report: getpagesize() = %10" SZ_FMT "\n" "pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n" "pack_report: core.packedGitLimit = %10" SZ_FMT "\n", - (unsigned long) getpagesize(), - (unsigned long) packed_git_window_size, - (unsigned long) packed_git_limit); + sz_fmt(getpagesize()), + sz_fmt(packed_git_window_size), + sz_fmt(packed_git_limit)); fprintf(stderr, "pack_report: pack_used_ctr = %10u\n" "pack_report: pack_mmap_calls = %10u\n" @@ -443,8 +445,7 @@ void pack_report(void) pack_used_ctr, pack_mmap_calls, pack_open_windows, peak_pack_open_windows, - (unsigned long) pack_mapped, - (unsigned long) peak_pack_mapped); + sz_fmt(pack_mapped), sz_fmt(peak_pack_mapped)); } static int check_packed_git_idx(const char *path, struct packed_git *p) From 98603195e96615b491384724bfff6564d31ad067 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 1 Dec 2007 17:49:10 +0100 Subject: [PATCH 0340/3720] skip t5512 because remote does not yet work Signed-off-by: Steffen Prohaska --- t/t5512-ls-remote.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 6ec5f7c48b..b3a6d6f341 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -4,6 +4,9 @@ test_description='git ls-remote' . ./test-lib.sh +say "git remote does not work in t/ - skipping" +test_done + test_expect_success setup ' >file && From 7ce819b333256b4ff1e1f2f72796b6f34d3c70d0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 1 Dec 2007 20:50:09 +0100 Subject: [PATCH 0341/3720] Clean up the MINGW section in the Makefile. We want to use whitespace around '=' consistently before we ask for inclusion in upstream. Signed-off-by: Johannes Sixt --- Makefile | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 39dbd2a142..32b6c0292a 100644 --- a/Makefile +++ b/Makefile @@ -496,25 +496,26 @@ ifeq ($(uname_S),IRIX64) BASIC_LDFLAGS += -L/usr/lib32 endif ifneq (,$(findstring MINGW,$(uname_S))) - NO_MMAP=YesPlease - NO_PREAD=YesPlease - NO_OPENSSL=YesPlease - NO_CURL=YesPlease - NO_SYMLINK_HEAD=YesPlease - NO_IPV6=YesPlease - NO_SETENV=YesPlease - NO_UNSETENV=YesPlease - NO_STRCASESTR=YesPlease - NO_STRLCPY=YesPlease + NO_MMAP = YesPlease + NO_PREAD = YesPlease + NO_OPENSSL = YesPlease + NO_CURL = YesPlease + NO_SYMLINK_HEAD = YesPlease + NO_IPV6 = YesPlease + NO_SETENV = YesPlease + NO_UNSETENV = YesPlease + NO_STRCASESTR = YesPlease + NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease NO_MKDTEMP = YesPlease - NO_SVN_TESTS=YesPlease - NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat + NO_SVN_TESTS = YesPlease + NO_PERL_MAKEMAKER = YesPlease + COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat + COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe From 2bd3a118a7e1bb6c047300ca3e3c9c890175e22c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 1 Dec 2007 21:36:07 +0100 Subject: [PATCH 0342/3720] Clean up the MINGW section in git-compat-util.h. The entries are now arranged in categories. inet_ntop(), kill(), and openlog() are unused and, hence, removed. Signed-off-by: Johannes Sixt --- Makefile | 6 ++ compat/mingw.c | 12 +-- git-compat-util.h | 216 ++++++++++++++++++++++++++-------------------- 3 files changed, 130 insertions(+), 104 deletions(-) diff --git a/Makefile b/Makefile index 32b6c0292a..c1e58a63ff 100644 --- a/Makefile +++ b/Makefile @@ -514,6 +514,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + NO_EXTRA_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o @@ -583,6 +584,11 @@ ifdef ZLIB_PATH endif EXTLIBS += -lz +ifndef NO_EXTRA_PROGRAMS + EXTRA_PROGRAMS += \ + git-daemon$X \ + git-imap-send$X +endif ifndef NO_OPENSSL OPENSSL_LIBSSL = -lssl ifdef OPENSSLDIR diff --git a/compat/mingw.c b/compat/mingw.c index e57c74e0ce..e74f148b27 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -181,11 +181,7 @@ unsigned int sleep (unsigned int __seconds) Sleep(__seconds*1000); return 0; } -const char *inet_ntop(int af, const void *src, - char *dst, size_t cnt) -{ - return NULL; -} + int mkstemp (char *__template) { char *filename = mktemp(__template); @@ -348,10 +344,6 @@ char *mingw_getcwd(char *pointer, int len) return ret; } -void openlog(const char *ident, int option, int facility) -{ -} - /* * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx * (Parsing C++ Command-Line Arguments) @@ -876,7 +868,7 @@ int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) return len; } -struct passwd *mingw_getpwuid(int uid) +struct passwd *getpwuid(int uid) { static char user_name[100]; static struct passwd p; diff --git a/git-compat-util.h b/git-compat-util.h index 5235d31f27..e2aebfb375 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -64,18 +64,14 @@ #include #include #include +#include +#include #ifndef __MINGW32__ #include #include #include #include #include -#else -int mkstemp (char *__template); -#endif -#include -#include -#ifndef __MINGW32__ #include #include #include @@ -91,7 +87,7 @@ int mkstemp (char *__template); #include #define _ALL_SOURCE 1 #endif -#endif +#endif /* !__MINGW32__ */ #ifndef NO_ICONV #include @@ -362,6 +358,10 @@ static inline FILE *xfdopen(int fd, const char *mode) return stream; } +#ifdef __MINGW32__ +int mkstemp(char *template); +#endif + static inline int xmkstemp(char *template) { int fd; @@ -445,6 +445,13 @@ static inline int strtol_i(char const *s, int base, int *result) #include +/* + * things that are not available in header files + */ + +typedef int pid_t; +#define hstrerror strerror + #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 @@ -455,6 +462,50 @@ static inline int strtol_i(char const *s, int base, int *result) #define S_IROTH 0 #define S_IXOTH 0 +#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ +#define WEXITSTATUS(x) ((x) & 0xff) +#define WIFSIGNALED(x) ((unsigned)(x) > 259) + +#define SIGKILL 0 +#define SIGCHLD 0 +#define SIGPIPE 0 +#define SIGALRM 100 + +#define F_GETFD 1 +#define F_SETFD 2 +#define FD_CLOEXEC 0x1 + +struct passwd { + char *pw_name; + char *pw_gecos; + char *pw_dir; +}; + +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; +#define POLLIN 1 +#define POLLHUP 2 + +typedef void (__cdecl *sig_handler_t)(int); +struct sigaction { + sig_handler_t sa_handler; + unsigned sa_flags; +}; +#define sigemptyset(x) (void)0 +#define SA_RESTART 0 + +struct itimerval { + struct timeval it_value, it_interval; +}; +#define ITIMER_REAL 0 + +/* + * trivial stubs + */ + static inline int readlink(const char *path, char *buf, size_t bufsiz) { errno = ENOSYS; return -1; } static inline int symlink(const char *oldpath, const char *newpath) @@ -465,72 +516,74 @@ static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) { errno = ENOSYS; return -1; } -static inline int kill(pid_t pid, int sig) -{ errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } - -typedef int pid_t; -extern pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); -extern void mingw_execvp(const char *cmd, char *const *argv); -#define execvp mingw_execvp -static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +static inline int fsync(int fd) +{ return 0; } +static inline int getppid(void) +{ return 1; } +static inline void sync(void) +{} +static inline int getuid() +{ return 1; } +static inline struct passwd *getpwnam(const char *name) +{ return NULL; } +static inline int fcntl(int fd, int cmd, long arg) { - if (options == 0) - return _cwait(status, pid, 0); - else - return errno = EINVAL, -1; + if (cmd == F_GETFD || cmd == F_SETFD) + return 0; + errno = EINVAL; + return -1; } -#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ -#define WEXITSTATUS(x) ((x) & 0xff) -#define WIFSIGNALED(x) ((unsigned)(x) > 259) -#define WTERMSIG(x) (x) -#define WNOHANG 1 -#define SIGKILL 0 -#define SIGCHLD 0 -#define SIGPIPE 0 +/* + * simple adaptors + */ -char **copy_environ(); -char **copy_env(char **env); -void env_unsetenv(char **env, const char *name); - -unsigned int sleep (unsigned int __seconds); -const char *inet_ntop(int af, const void *src, - char *dst, size_t cnt); -int gettimeofday(struct timeval *tv, void *tz); -int pipe(int filedes[2]); - -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; -int poll(struct pollfd *ufds, unsigned int nfds, int timeout); -#define POLLIN 1 -#define POLLHUP 2 - -static inline int git_mkdir(const char *path, int mode) +static inline int mingw_mkdir(const char *path, int mode) { return mkdir(path); } -#define mkdir git_mkdir +#define mkdir mingw_mkdir -static inline int git_unlink(const char *pathname) { +static inline int mingw_unlink(const char *pathname) +{ /* read-only files cannot be removed */ chmod(pathname, 0666); return unlink(pathname); } -#define unlink git_unlink +#define unlink mingw_unlink + +static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +{ + if (options == 0) + return _cwait(status, pid, 0); + errno = EINVAL; + return -1; +} + +/* + * implementations of missing functions + */ + +int pipe(int filedes[2]); +unsigned int sleep (unsigned int seconds); +int gettimeofday(struct timeval *tv, void *tz); +int poll(struct pollfd *ufds, unsigned int nfds, int timeout); +struct tm *gmtime_r(const time_t *timep, struct tm *result); +struct tm *localtime_r(const time_t *timep, struct tm *result); +int getpagesize(void); /* defined in MinGW's libgcc.a */ +struct passwd *getpwuid(int uid); +int setitimer(int type, struct itimerval *in, struct itimerval *out); +int sigaction(int sig, struct sigaction *in, struct sigaction *out); + +/* + * replacements of existing functions + */ int mingw_open (const char *filename, int oflags, ...); #define open mingw_open -#include -struct tm *gmtime_r(const time_t *timep, struct tm *result); -struct tm *localtime_r(const time_t *timep, struct tm *result); -#define hstrerror strerror - char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd @@ -546,11 +599,6 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); int mingw_rename(const char*, const char*); #define rename mingw_rename -static inline int fsync(int fd) { return 0; } -static inline int getppid(void) { return 1; } -static inline void sync(void) {} -extern int getpagesize(void); /* defined in MinGW's libgcc.a */ - /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. * struct stat is redefined because it lacks the st_blocks member. @@ -573,45 +621,25 @@ static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); #define vsnprintf mingw_vsnprintf -struct passwd { - char *pw_name; - char *pw_gecos; - char *pw_dir; -}; -struct passwd *mingw_getpwuid(int uid); -#define getpwuid mingw_getpwuid -static inline int getuid() { return 1; } -static inline struct passwd *getpwnam(const char *name) { return NULL; } - -struct itimerval { - struct timeval it_value, it_interval; -}; -int setitimer(int type, struct itimerval *in, struct itimerval *out); -#define ITIMER_REAL 0 - -typedef void (__cdecl *sig_handler_t)(int); -struct sigaction { - sig_handler_t sa_handler; - unsigned sa_flags; -}; -int sigaction(int sig, struct sigaction *in, struct sigaction *out); -#define sigemptyset(x) (void)0 -#define SA_RESTART 0 -#define SIGALRM 100 -sig_handler_t mingw_signal(int sig, sig_handler_t handler); -#define signal mingw_signal - -#define F_GETFD 1 -#define F_SETFD 2 -#define FD_CLOEXEC 0x1 -static inline int mingw_fcntl(int fd, int cmd, long arg) -{ return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } -#define fcntl mingw_fcntl +pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); +void mingw_execvp(const char *cmd, char *const *argv); +#define execvp mingw_execvp static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); } #define ntohl git_ntohl +sig_handler_t mingw_signal(int sig, sig_handler_t handler); +#define signal mingw_signal + +/* + * helpers + */ + +char **copy_environ(); +char **copy_env(char **env); +void env_unsetenv(char **env, const char *name); + #endif /* __MINGW32__ */ #endif From dfc991a98a22c8f440345ced7a906d90edf410dc Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Dec 2007 19:35:00 +0100 Subject: [PATCH 0343/3720] Clean up compat/mingw.c. The PATH related functions are now static and can lose the mingw_ prefix. path_lookup() no longer looks in the current directory, and it will now actually return NULL. Previously, it returned the input program name as a fallback. Signed-off-by: Johannes Sixt --- compat/mingw.c | 50 ++++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index e74f148b27..d32722ee26 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,4 +1,3 @@ -#include #include "../git-compat-util.h" #include "../strbuf.h" @@ -176,15 +175,15 @@ int mingw_fstat(int fd, struct mingw_stat *buf) return -1; } -unsigned int sleep (unsigned int __seconds) +unsigned int sleep (unsigned int seconds) { - Sleep(__seconds*1000); + Sleep(seconds*1000); return 0; } -int mkstemp (char *__template) +int mkstemp(char *template) { - char *filename = mktemp(__template); + char *filename = mktemp(template); if (filename == NULL) return -1; return open(filename, O_RDWR | O_CREAT, 0600); @@ -314,8 +313,6 @@ repeat: return 0; } -#include - struct tm *gmtime_r(const time_t *timep, struct tm *result) { memcpy(result, gmtime(timep), sizeof(struct tm)); @@ -441,7 +438,7 @@ static const char *parse_interpreter(const char *cmd) /* * Splits the PATH into parts. */ -static char **mingw_get_path_split(void) +static char **get_path_split(void) { char *p, **path, *envpath = getenv("PATH"); int i, n = 0; @@ -477,7 +474,7 @@ static char **mingw_get_path_split(void) return path; } -static void mingw_free_path_split(char **path) +static void free_path_split(char **path) { if (!path) return; @@ -509,9 +506,8 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on * Determines the absolute path of cmd using the the split path in path. * If cmd contains a slash or backslash, no lookup is performed. */ -static char *mingw_path_lookup(const char *cmd, char **path, int exe_only) +static char *path_lookup(const char *cmd, char **path, int exe_only) { - char **p = path; char *prog = NULL; int len = strlen(cmd); int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe"); @@ -519,14 +515,9 @@ static char *mingw_path_lookup(const char *cmd, char **path, int exe_only) if (strchr(cmd, '/') || strchr(cmd, '\\')) prog = xstrdup(cmd); - while (!prog && *p) { - prog = lookup_prog(*p++, cmd, isexe, exe_only); - } - if (!prog) { - prog = lookup_prog(".", cmd, isexe, exe_only); - if (!prog) - prog = xstrdup(cmd); - } + while (!prog && *path) + prog = lookup_prog(*path++, cmd, isexe, exe_only); + return prog; } @@ -630,8 +621,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) { pid_t pid; - char **path = mingw_get_path_split(); - char *prog = mingw_path_lookup(cmd, path, 0); + char **path = get_path_split(); + char *prog = path_lookup(cmd, path, 0); if (!prog) { errno = ENOENT; @@ -642,7 +633,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) if (interpr) { const char *argv0 = argv[0]; - char *iprog = mingw_path_lookup(interpr, path, 1); + char *iprog = path_lookup(interpr, path, 1); argv[0] = prog; if (!iprog) { errno = ENOENT; @@ -658,7 +649,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) pid = mingw_spawnve(prog, argv, env, 0); free(prog); } - mingw_free_path_split(path); + free_path_split(path); return pid; } @@ -671,8 +662,8 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env) if (!interpr) return 0; - path = mingw_get_path_split(); - prog = mingw_path_lookup(interpr, path, 1); + path = get_path_split(); + prog = path_lookup(interpr, path, 1); if (prog) { int argc = 0; const char **argv2; @@ -691,7 +682,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env) free(prog); free(argv2); } - mingw_free_path_split(path); + free_path_split(path); return pid; } @@ -712,8 +703,8 @@ static void mingw_execve(const char *cmd, char *const *argv, char *const *env) void mingw_execvp(const char *cmd, char *const *argv) { - char **path = mingw_get_path_split(); - char *prog = mingw_path_lookup(cmd, path, 0); + char **path = get_path_split(); + char *prog = path_lookup(cmd, path, 0); if (prog) { mingw_execve(prog, argv, environ); @@ -721,7 +712,7 @@ void mingw_execvp(const char *cmd, char *const *argv) } else errno = ENOENT; - mingw_free_path_split(path); + free_path_split(path); } char **copy_environ() @@ -882,7 +873,6 @@ struct passwd *getpwuid(int uid) return &p; } - static HANDLE timer_event; static HANDLE timer_thread; static int timer_interval; From f6df056f6cda03bdb102ab2e2d928872456135da Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Dec 2007 20:26:24 +0100 Subject: [PATCH 0344/3720] Rework environment manipulation. A lookup routine is extracted from env_unsetenv() because we will need it for env_setenv(). The environment data is now released, too. Signed-off-by: Johannes Sixt --- compat/mingw.c | 61 ++++++++++++++++++++++++++--------------------- git-compat-util.h | 4 ++-- run-command.c | 4 ++-- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d32722ee26..fa5b9cd379 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -717,41 +717,48 @@ void mingw_execvp(const char *cmd, char *const *argv) char **copy_environ() { - return copy_env(environ); + char **env; + int i = 0; + while (environ[i]) + i++; + env = xmalloc((i+1)*sizeof(*env)); + for (i = 0; environ[i]; i++) + env[i] = xstrdup(environ[i]); + env[i] = NULL; + return env; } -char **copy_env(char **env) +void free_env(char **env) { - char **s; - int n = 1; - for (s = env; *s; s++) - n++; - s = xmalloc(n*sizeof(char *)); - memcpy(s, env, n*sizeof(char *)); - return s; + int i; + for (i = 0; env[i]; i++) + free(env[i]); + free(env); +} + +static int lookup_env(char **env, const char *name) +{ + int i; + size_t nmln = strlen(name); + + for (i = 0; env[i]; i++) { + if (0 == strncmp(env[i], name, nmln) + && '=' == env[i][nmln]) + /* matches */ + return i; + } + return -1; } void env_unsetenv(char **env, const char *name) { - int src, dst; - size_t nmln; + int i = lookup_env(env, name); + if (i < 0) + return; - nmln = strlen(name); - - for (src = dst = 0; env[src]; ++src) { - size_t enln; - enln = strlen(env[src]); - if (enln > nmln) { - /* might match, and can test for '=' safely */ - if (0 == strncmp (env[src], name, nmln) - && '=' == env[src][nmln]) - /* matches, so skip */ - continue; - } - env[dst] = env[src]; - ++dst; - } - env[dst] = NULL; + free(env[i]); + for (; env[i]; i++) + env[i] = env[i+1]; } /* this is the first function to call into WS_32; initialize it */ diff --git a/git-compat-util.h b/git-compat-util.h index e2aebfb375..12426951fa 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -636,8 +636,8 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); * helpers */ -char **copy_environ(); -char **copy_env(char **env); +char **copy_environ(void); +void free_environ(void); void env_unsetenv(char **env, const char *name); #endif /* __MINGW32__ */ diff --git a/run-command.c b/run-command.c index cf1377de64..8e0daab62a 100644 --- a/run-command.c +++ b/run-command.c @@ -162,8 +162,8 @@ int start_command(struct child_process *cmd) cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); - /* TODO: if (cmd->env) free env; */ - + if (cmd->env) + free(env); if (cmd->git_cmd) strbuf_release(&git_cmd); From 9a930a2ecb95030b0b3b1ec651c1307c5e57073c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Dec 2007 21:39:19 +0100 Subject: [PATCH 0345/3720] Implement setting of environment variables in spawned programs. Signed-off-by: Johannes Sixt --- compat/mingw.c | 34 +++++++++++++++++++++++++--------- git-compat-util.h | 2 +- run-command.c | 8 ++------ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index fa5b9cd379..553e8f3ac4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -736,10 +736,9 @@ void free_env(char **env) free(env); } -static int lookup_env(char **env, const char *name) +static int lookup_env(char **env, const char *name, size_t nmln) { int i; - size_t nmln = strlen(name); for (i = 0; env[i]; i++) { if (0 == strncmp(env[i], name, nmln) @@ -750,15 +749,32 @@ static int lookup_env(char **env, const char *name) return -1; } -void env_unsetenv(char **env, const char *name) +/* + * If name contains '=', then sets the variable, otherwise it unsets it + */ +char **env_setenv(char **env, const char *name) { - int i = lookup_env(env, name); - if (i < 0) - return; + char *eq = strchrnul(name, '='); + int i = lookup_env(env, name, eq-name); - free(env[i]); - for (; env[i]; i++) - env[i] = env[i+1]; + if (i < 0) { + if (*eq) { + for (i = 0; env[i]; i++) + ; + env = xrealloc(env, (i+2)*sizeof(*env)); + env[i] = xstrdup(name); + env[i+1] = NULL; + } + } + else { + free(env[i]); + if (*eq) + env[i] = xstrdup(name); + else + for (; env[i]; i++) + env[i] = env[i+1]; + } + return env; } /* this is the first function to call into WS_32; initialize it */ diff --git a/git-compat-util.h b/git-compat-util.h index 12426951fa..120f88c943 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -638,7 +638,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); char **copy_environ(void); void free_environ(void); -void env_unsetenv(char **env, const char *name); +char **env_setenv(char **env, const char *name); #endif /* __MINGW32__ */ diff --git a/run-command.c b/run-command.c index 8e0daab62a..37d4d7fafc 100644 --- a/run-command.c +++ b/run-command.c @@ -146,12 +146,8 @@ int start_command(struct child_process *cmd) die("chdir in start_command() not implemented"); if (cmd->env) { env = copy_environ(); - for (; *cmd->env; cmd->env++) { - if (strchr(*cmd->env, '=')) - die("setting environment in start_command() not implemented"); - else - env_unsetenv(env, *cmd->env); - } + for (; *cmd->env; cmd->env++) + env = env_setenv(env, *cmd->env); } if (cmd->git_cmd) { From 864e1c96c242174e4345c2443f7ab34fb9102619 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Dec 2007 21:39:59 +0100 Subject: [PATCH 0346/3720] Exclude t4023-diff-rename-typechange - symbolic links are not available. Signed-off-by: Johannes Sixt --- t/t4023-diff-rename-typechange.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 255604effd..7a2a05ae20 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -4,6 +4,11 @@ test_description='typechange rename detection' . ./test-lib.sh +if test "$no_symlinks"; then + say "symbolic links not supported - skipping test" + test_done; +fi + test_expect_success setup ' rm -f foo bar && From d63abd8dc5e63c0d174d1ddfe34dd1957e5a692b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 7 Dec 2007 22:45:20 +0100 Subject: [PATCH 0347/3720] Fixup the clean-up of environment handling. Signed-off-by: Johannes Sixt --- compat/mingw.c | 2 +- git-compat-util.h | 2 +- run-command.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 553e8f3ac4..8bbe21bb67 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -728,7 +728,7 @@ char **copy_environ() return env; } -void free_env(char **env) +void free_environ(char **env) { int i; for (i = 0; env[i]; i++) diff --git a/git-compat-util.h b/git-compat-util.h index 120f88c943..ab7b668124 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -637,7 +637,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); */ char **copy_environ(void); -void free_environ(void); +void free_environ(char **env); char **env_setenv(char **env, const char *name); #endif /* __MINGW32__ */ diff --git a/run-command.c b/run-command.c index 37d4d7fafc..5ed338c0cb 100644 --- a/run-command.c +++ b/run-command.c @@ -159,7 +159,7 @@ int start_command(struct child_process *cmd) cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); if (cmd->env) - free(env); + free_environ(env); if (cmd->git_cmd) strbuf_release(&git_cmd); From a1e84247e94e39fd8ff5dace0cfb9fa35c562a61 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 8 Dec 2007 15:33:04 +0100 Subject: [PATCH 0348/3720] t7501-commit: Skip testing '--interactive' msysgit does not yet support Git.pm, which is required by git commit --interactive. This commit modifies t7501 to skip testing git commit --interactive. Signed-off-by: Steffen Prohaska --- t/t7501-commit.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 19c4b2c556..dd4bf28526 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -119,6 +119,7 @@ test_expect_success \ "echo 'gak' >file && \ git-commit -m 'author' --author 'Rubber Duck ' -a" +echo "SKIP because msysgit does not support Git.pm" || test_expect_success \ "interactive add" \ "echo 7 | git-commit --interactive | grep 'What now'" From 4a8d948eaccda45f1afded4dc545e35207a0847f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 20:51:36 +0100 Subject: [PATCH 0349/3720] Fix prefix_filename() function. The previous implementation translated '\' to '/' on non-Windows, too (in those cases where the prefix was actually prepended to the path). Signed-off-by: Johannes Sixt --- setup.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/setup.c b/setup.c index a89152d630..2cbe8733a5 100644 --- a/setup.c +++ b/setup.c @@ -82,21 +82,23 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; - char *p; #ifndef __MINGW32__ if (!pfx || !*pfx || is_absolute_path(arg)) return arg; + memcpy(path, pfx, pfx_len); + strcpy(path + pfx_len, arg); #else - /* don't add prefix to absolute paths */ + char *p; + /* don't add prefix to absolute paths, but still replace '\' by '/' */ if (is_absolute_path(arg)) pfx_len = 0; else -#endif - memcpy(path, pfx, pfx_len); + memcpy(path, pfx, pfx_len); strcpy(path + pfx_len, arg); for (p = path + pfx_len; *p; p++) if (*p == '\\') *p = '/'; +#endif return path; } From 31cda4934813255c319e0f10791903ead783bbba Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 21:47:19 +0100 Subject: [PATCH 0350/3720] Clean up pager.c (Windows specific part). Signed-off-by: Johannes Sixt --- pager.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pager.c b/pager.c index de1bc799f5..c9f7e62534 100644 --- a/pager.c +++ b/pager.c @@ -1,8 +1,8 @@ #include "cache.h" /* - * This is split up from the rest of git so that we might do - * something different on Windows, for example. + * This is split up from the rest of git so that we can do + * something different on Windows. */ #ifndef __MINGW32__ @@ -24,12 +24,12 @@ static void run_pager(const char *pager) #else #include "run-command.h" -const char *pager_argv[] = { "sh", "-c", NULL, NULL }; +static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; static struct child_process pager_process = { .argv = pager_argv, .in = -1 }; -static void collect_pager(void) +static void wait_for_pager(void) { fflush(stdout); close(1); /* signals EOF to pager */ @@ -99,6 +99,6 @@ void setup_pager(void) close(pager_process.in); /* this makes sure that the parent terminates after the pager */ - atexit(collect_pager); + atexit(wait_for_pager); #endif } From 71d36f430104ac845093cf91e79b1b31952ac314 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 23:09:34 +0100 Subject: [PATCH 0351/3720] Add #ifdef __MINGW32__ in two places Signed-off-by: Johannes Sixt --- connect.c | 7 ++++++- path.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index c1483bf4f8..12903986f3 100644 --- a/connect.c +++ b/connect.c @@ -523,8 +523,13 @@ struct child_process *git_connect(int fd[2], const char *url_orig, end = host; path = strchr(end, c); +#ifdef __MINGW32__ /* host must have at least 2 chars to catch DOS C:/path */ - if (path && path - end > 1) { + if (path && path - end > 1) +#else + if (path) +#endif + { if (c == ':') { protocol = PROTO_SSH; *path++ = '\0'; diff --git a/path.c b/path.c index e264bb34a9..7f1853939d 100644 --- a/path.c +++ b/path.c @@ -75,11 +75,13 @@ int git_mkstemp(char *path, size_t len, const char *template) size_t n; tmp = getenv("TMPDIR"); +#ifdef __MINGW32__ /* on Windows it is TMP and TEMP */ if (!tmp) tmp = getenv("TMP"); if (!tmp) tmp = getenv("TEMP"); +#endif if (!tmp) tmp = "/tmp"; n = snprintf(path, len, "%s/%s", tmp, template); From b54486636e4f7ef7758e4cc0158c1446d263b253 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 23:12:41 +0100 Subject: [PATCH 0352/3720] Rename is_path_absolute() in sha1_file.c to offset_1st_component(). This better describes the purpose of the function. Signed-off-by: Johannes Sixt --- sha1_file.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index 1984e35823..e7deefc769 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -83,20 +83,18 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) return 0; } -/* returns the number of chars to skip to first component */ -static inline int is_path_absolute(const char *path) +static inline int offset_1st_component(const char *path) { #ifdef __MINGW32__ if (isalpha(path[0]) && path[1] == ':') return 2 + (path[2] == '/'); - /* TODO: C:dir/file 'relative' paths are not catered for */ #endif return *path == '/'; } int safe_create_leading_directories(char *path) { - char *pos = path + is_path_absolute(path); + char *pos = path + offset_1st_component(path); struct stat st; while (pos) { From 370a1dad18129837c95188f91edef6e3e12cd9d0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 23:15:32 +0100 Subject: [PATCH 0353/3720] Don't make the extra check for errno == EINVAL MinGW specific. This saves an #ifdef. There is precedent for an extra check without #ifdef brackets already in refs.c (Solaris). The check for EINVAL shouldn't hurt. Signed-off-by: Johannes Sixt --- write_or_die.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/write_or_die.c b/write_or_die.c index 40b046acb0..f3b8566ab8 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -34,16 +34,12 @@ void maybe_flush_or_die(FILE *f, const char *desc) return; } if (fflush(f)) { -#ifndef __MINGW32__ - if (errno == EPIPE) -#else /* * On Windows, EPIPE is returned only by the first write() * after the reading end has closed its handle; subsequent * write()s return EINVAL. */ if (errno == EPIPE || errno == EINVAL) -#endif exit(0); die("write failure on %s: %s", desc, strerror(errno)); } From 06bb831308532f7bc5bd00f634e60586e998c518 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Dec 2007 21:47:44 +0100 Subject: [PATCH 0354/3720] t7201-co: Work around whitespace damaged messages.expect Signed-off-by: Johannes Sixt --- t/t7201-co.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 73d8a00e2c..be9271543b 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -185,7 +185,7 @@ If you want to create a new branch from this checkout, you may do so HEAD is now at 7329388... Initial A one, A two EOF ) && - git diff messages.expect messages && + git diff -w messages.expect messages && H=$(git rev-parse --verify HEAD) && M=$(git show-ref -s --verify refs/heads/master) && test "z$H" = "z$M" && From 0574f944567faf0d0129e28a57705c931441b1d8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Dec 2007 22:09:18 +0100 Subject: [PATCH 0355/3720] t7503, t7504: Skip tests of non-executable hook if execute bit doesn't work Signed-off-by: Johannes Sixt --- t/t7503-pre-commit-hook.sh | 6 ++++++ t/t7504-commit-msg-hook.sh | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh index d787cac2f7..5c13097bda 100755 --- a/t/t7503-pre-commit-hook.sh +++ b/t/t7503-pre-commit-hook.sh @@ -69,6 +69,10 @@ test_expect_success '--no-verify with failing hook' ' ' chmod -x "$HOOK" +if test "$(git config --bool core.filemode)" = false; then + say "executable bit not honored - skipping tests of non-executable hook" +else + test_expect_success 'with non-executable hook' ' echo "content" >> file && @@ -85,4 +89,6 @@ test_expect_success '--no-verify with non-executable hook' ' ' +fi # non-executable hooks + test_done diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh index 751b11300b..12ed793a48 100755 --- a/t/t7504-commit-msg-hook.sh +++ b/t/t7504-commit-msg-hook.sh @@ -133,6 +133,10 @@ test_expect_success '--no-verify with failing hook (editor)' ' ' chmod -x "$HOOK" +if test "$(git config --bool core.filemode)" = false; then + say "executable bit not honored - skipping tests of non-executable hook" +else + test_expect_success 'with non-executable hook' ' echo "content" >> file && @@ -167,6 +171,8 @@ test_expect_success '--no-verify with non-executable hook (editor)' ' ' +fi # non-executable hooks + # now a hook that edits the commit message cat > "$HOOK" <<'EOF' #!/bin/sh From 3805d587572fd50b2e8bb6af6b1dbccffb6807e5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 10 Dec 2007 12:55:35 +0100 Subject: [PATCH 0356/3720] Avoid the "dup dance" in wt_status_print_verbose() when possible. If the status output already goes to stdout, then it is not necessary to redirect stdout for the diff machinery. (This case hangs on Windows for unknown reasons.) Signed-off-by: Johannes Sixt --- wt-status.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/wt-status.c b/wt-status.c index 51c1879691..9a2d3c65b7 100644 --- a/wt-status.c +++ b/wt-status.c @@ -321,15 +321,17 @@ static void wt_status_print_untracked(struct wt_status *s) static void wt_status_print_verbose(struct wt_status *s) { struct rev_info rev; - int saved_stdout; + int saved_stdout = -1; fflush(s->fp); /* Sigh, the entire diff machinery is hardcoded to output to * stdout. Do the dup-dance...*/ - saved_stdout = dup(STDOUT_FILENO); - if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) - die("couldn't redirect stdout\n"); + if (fileno(s->fp) != STDOUT_FILENO) { + saved_stdout = dup(STDOUT_FILENO); + if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) + die("couldn't redirect stdout\n"); + } init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, s->reference); @@ -340,7 +342,7 @@ static void wt_status_print_verbose(struct wt_status *s) fflush(stdout); - if (dup2(saved_stdout, STDOUT_FILENO) < 0) + if (saved_stdout >= 0 && dup2(saved_stdout, STDOUT_FILENO) < 0) die("couldn't restore stdout\n"); close(saved_stdout); } From 8f4e9dca13aba080505aa95897de2833b1f421d6 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Dec 2007 15:40:11 +0100 Subject: [PATCH 0357/3720] Enhance the dup-dance in wt-status to work around t7502-commit.sh hang Seems like Windows has some problems if you do too much dup()ing around. Work around these problems by dup()ing yet one more time. Signed-off-by: Johannes Schindelin --- wt-status.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wt-status.c b/wt-status.c index 51c1879691..0b8a73fd44 100644 --- a/wt-status.c +++ b/wt-status.c @@ -321,15 +321,17 @@ static void wt_status_print_untracked(struct wt_status *s) static void wt_status_print_verbose(struct wt_status *s) { struct rev_info rev; - int saved_stdout; + int saved_stdout, redirected_stdout; fflush(s->fp); /* Sigh, the entire diff machinery is hardcoded to output to * stdout. Do the dup-dance...*/ saved_stdout = dup(STDOUT_FILENO); - if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) + redirected_stdout = dup(fileno(s->fp)); + if (saved_stdout < 0 || dup2(redirected_stdout, STDOUT_FILENO) < 0) die("couldn't redirect stdout\n"); + close(redirected_stdout); init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, s->reference); From 28456eeb0e887f87d6029fd49d7b4ad1e04b4e99 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 16 Dec 2007 23:01:37 +0100 Subject: [PATCH 0358/3720] Revert "Enhance the dup-dance in wt-status to work around t7502-commit.sh hang" This reverts commit 8f4e9dca13aba080505aa95897de2833b1f421d6. We'll instead take the solution from mingw/master with the next merge. --- wt-status.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wt-status.c b/wt-status.c index 0b8a73fd44..51c1879691 100644 --- a/wt-status.c +++ b/wt-status.c @@ -321,17 +321,15 @@ static void wt_status_print_untracked(struct wt_status *s) static void wt_status_print_verbose(struct wt_status *s) { struct rev_info rev; - int saved_stdout, redirected_stdout; + int saved_stdout; fflush(s->fp); /* Sigh, the entire diff machinery is hardcoded to output to * stdout. Do the dup-dance...*/ saved_stdout = dup(STDOUT_FILENO); - redirected_stdout = dup(fileno(s->fp)); - if (saved_stdout < 0 || dup2(redirected_stdout, STDOUT_FILENO) < 0) + if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) die("couldn't redirect stdout\n"); - close(redirected_stdout); init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, s->reference); From 5877600179068559e592bc0ab907e47fff26dcaa Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 10:54:08 +0200 Subject: [PATCH 0359/3720] MSYS: local clone must use the drive letter in absolute paths. The default of pwd of MSYS's bash and /bin/pwd are to use /c/rest/of/path notation instead of c:/rest/of/path. But the former is not supported by programs that use the standard C runtime (instead of MSYS's runtime). Hence, we must make sure that only drive letter notations are generated by using pwd's -W option. Signed-off-by: Johannes Sixt --- git-clone.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 557c72f127..b62fd24d21 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -66,6 +66,19 @@ case $(uname -s) in xargs --no-run-if-empty \ cp $cp_arg --target-directory="$2" --parents } + # pwd must return a path with a drive letter + bin_pwd() { + # there are no symlinks to resolve: /bin/pwd is not needed + builtin pwd -W + } + pwd() { + builtin pwd -W + } + ;; +*) + bin_pwd() { + /bin/pwd + } ;; esac @@ -77,11 +90,11 @@ eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?) get_repo_base() { ( - cd "`/bin/pwd -W`" && + cd "$(bin_pwd)" && cd "$1" || cd "$1.git" && { cd .git - pwd -W + pwd } ) 2>/dev/null } From 40c7f8a61c569cef9caf258c8c1d2663627384d3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 26 Dec 2007 20:35:45 +0100 Subject: [PATCH 0360/3720] Revert "Strip \r from the input." This reverts commit 5bc08ee66f49beedb5327446ff147e92345df65c, which is no longer needed since git-ls-remote is built-in. --- builtin-fmt-merge-msg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index c7de27c849..6163bd4975 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -95,8 +95,6 @@ static int handle_line(char *line) return 3; if (line[len - 1] == '\n') - line[len - 1] = 0, --len; - if (line[len - 1] == '\r') line[len - 1] = 0; line += 42; From 301de2ab75f77c4be6f3d83ff2b4201b6b3bd25c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 16 Dec 2007 22:46:49 +0100 Subject: [PATCH 0361/3720] help (mingw): Cleaned up whitespace indentation The separate block for the ShellExecute code is no longer needed and therefore cleand up. Also included is minor rewording of the error message if the HTML page is not found. Signed-off-by: Steffen Prohaska --- help.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/help.c b/help.c index dcb6a3f6c5..146d131820 100644 --- a/help.c +++ b/help.c @@ -336,28 +336,26 @@ static void show_info_page(const char *git_cmd) static void show_html_page(const char *git_cmd) { #ifdef __MINGW32__ - { - const char* exec_path = git_exec_path(); - char *htmlpath = make_native_separator( - mkpath("%s/../doc/git/html/%s.html" - , exec_path - , git_cmd) - ); + const char* exec_path = git_exec_path(); + char *htmlpath = make_native_separator( + mkpath("%s/../doc/git/html/%s.html" + , exec_path + , git_cmd) + ); + if (!file_exists(htmlpath)) { + htmlpath = make_native_separator( + mkpath("%s/../doc/git/html/git-%s.html" + , exec_path + , git_cmd) + ); if (!file_exists(htmlpath)) { - htmlpath = make_native_separator( - mkpath("%s/../doc/git/html/git-%s.html" - , exec_path - , git_cmd) - ); - if (!file_exists(htmlpath)) { - fprintf(stderr, "Can't find help for '%s'.\n" - , git_cmd); - exit(1); - } + fprintf(stderr, "Can't find HTML help for '%s'.\n" + , git_cmd); + exit(1); } - printf("Launching default browser to display HTML help ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } + printf("Launching default browser to display HTML help ...\n"); + ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); #else const char *page = cmd_to_page(git_cmd); execl_git_cmd("help--browse", page, NULL); From bc8e453867b6ae950ae4333647f7f5e368ba7b15 Mon Sep 17 00:00:00 2001 From: Brian Downing Date: Fri, 16 Nov 2007 22:28:13 -0600 Subject: [PATCH 0362/3720] mingw-compat: Add simplified merge sort implementation from glibc qsort in Windows 2000 (and possibly other older Windows' C libraries) is a Quicksort with the usual O(n^2) worst case. Unfortunately, sorting Git trees seems to get very close to that worst case quite often: $ /git/gitbad runstatus # On branch master qsort, nmemb = 30842 done, 237838087 comparisons. This patch adds a simplified version of the merge sort that is glibc's qsort(3). As a merge sort, this needs a temporary array equal in size to the array that is to be sorted. The complexity that was removed is: * Doing direct stores for word-size and -aligned data. * Falling back to quicksort if the allocation required to perform the merge sort would likely push the machine into swap. Even with these simplifications, this seems to outperform the Windows qsort(3) implementation, even in Windows XP (where it is "fixed" and doesn't trigger O(n^2) complexity on trees). [jes: moved into compat/qsort.c, as per Johannes Sixt's suggestion] Signed-off-by: Brian Downing Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Schindelin --- Makefile | 8 +++++++ compat/qsort.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 6 +++++ 3 files changed, 74 insertions(+) create mode 100644 compat/qsort.c diff --git a/Makefile b/Makefile index a40e71c30d..448a22e123 100644 --- a/Makefile +++ b/Makefile @@ -136,6 +136,9 @@ all:: # Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit # parallel delta searching when packing objects. # +# Define NEEDS_QUICK_QSORT if your qsort() implementation has O(n^2) +# worst case complexity. +# GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @"$(SHELL_PATH)" ./GIT-VERSION-GEN @@ -523,6 +526,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease NO_R_TO_GCC_LINKER = YesPlease + NEEDS_QUICK_QSORT = YesPlease NO_EXTRA_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -741,6 +745,10 @@ ifdef NO_MEMMEM COMPAT_CFLAGS += -DNO_MEMMEM COMPAT_OBJS += compat/memmem.o endif +ifdef NEEDS_QUICK_QSORT + COMPAT_CFLAGS += -DNEEDS_QUICK_QSORT + COMPAT_OBJS += compat/qsort.o +endif ifdef THREADED_DELTA_SEARCH BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH diff --git a/compat/qsort.c b/compat/qsort.c new file mode 100644 index 0000000000..734866e5bc --- /dev/null +++ b/compat/qsort.c @@ -0,0 +1,60 @@ +#include "../git-compat-util.h" + +/* This merge sort implementation is simplified from glibc's. */ +static void msort_with_tmp(void *b, size_t n, size_t s, + int (*cmp)(const void *, const void *), + char *t) +{ + char *tmp; + char *b1, *b2; + size_t n1, n2; + + if (n <= 1) + return; + + n1 = n / 2; + n2 = n - n1; + b1 = b; + b2 = (char *)b + (n1 * s); + + msort_with_tmp(b1, n1, s, cmp, t); + msort_with_tmp(b2, n2, s, cmp, t); + + tmp = t; + + while (n1 > 0 && n2 > 0) { + if (cmp(b1, b2) <= 0) { + memcpy(tmp, b1, s); + tmp += s; + b1 += s; + --n1; + } else { + memcpy(tmp, b2, s); + tmp += s; + b2 += s; + --n2; + } + } + if (n1 > 0) + memcpy(tmp, b1, n1 * s); + memcpy(b, t, (n - n2) * s); +} + +void git_qsort(void *b, size_t n, size_t s, + int (*cmp)(const void *, const void *)) +{ + const size_t size = n * s; + + if (size < 1024) { + char buf[size]; /* gcc-ism */ + + /* The temporary array is small, so put it on + the stack. */ + msort_with_tmp(b, n, s, cmp, buf); + } else { + /* It's somewhat large, so malloc it. */ + char *tmp = malloc(size); + msort_with_tmp(b, n, s, cmp, tmp); + free(tmp); + } +} diff --git a/git-compat-util.h b/git-compat-util.h index 5a81bc9e76..0f92d1d570 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -645,4 +645,10 @@ extern __attribute__((noreturn)) int git_exit(int code); #endif /* __MINGW32__ */ +#ifdef NEEDS_QUICK_QSORT +void git_qsort(void *base, size_t nmemb, size_t size, + int(*compar)(const void *, const void *)); +#define qsort git_qsort +#endif + #endif From d3f72ce4f0c2d5aac2e27df4e866dac628994b2d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 1 Jan 2008 22:15:21 +0100 Subject: [PATCH 0363/3720] When installing, be prepared that template_dir may be relative. Since the Makefile in the template/ subdirectory is only used to install the templates, we do not simply pass down the setting of template_dir when it is relative, but construct the intended destination in a new variable: A relative template_dir is relative to gitexecdir. Signed-off-by: Johannes Sixt --- Makefile | 9 ++++++++- templates/Makefile | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 0029b5032a..3ad839eaa4 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,7 @@ GITWEB_FAVICON = git-favicon.png GITWEB_SITE_HEADER = GITWEB_SITE_FOOTER = -export prefix bindir gitexecdir sharedir template_dir htmldir sysconfdir +export prefix bindir gitexecdir sharedir htmldir sysconfdir CC = gcc AR = ar @@ -1061,6 +1061,13 @@ remove-dashes: ### Installation rules +ifeq ($(firstword $(subst /, ,$(template_dir))),..) +template_instdir = $(gitexecdir)/$(template_dir) +else +template_instdir = $template_dir +endif +export template_instdir + install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' diff --git a/templates/Makefile b/templates/Makefile index e274eb3efa..0ed2f35003 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -8,14 +8,14 @@ INSTALL ?= install TAR ?= tar RM ?= rm -f prefix ?= $(HOME) -template_dir = $(prefix)/share/git-core/templates +template_instdir ?= $(prefix)/share/git-core/templates # DESTDIR= # set NOEXECTEMPL to non-empty to change the names of hook scripts # so that the tools will not find them # Shell quote (do not use $(call) to accommodate ancient setups); DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) -template_dir_SQ = $(subst ','\'',$(template_dir)) +template_instdir_SQ = $(subst ','\'',$(template_instdir)) all: boilerplates.made custom @@ -52,6 +52,6 @@ clean: $(RM) -r blt boilerplates.made install: all - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(template_dir_SQ)' + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(template_instdir_SQ)' (cd blt && $(TAR) cf - .) | \ - (cd '$(DESTDIR_SQ)$(template_dir_SQ)' && $(TAR) xf -) + (cd '$(DESTDIR_SQ)$(template_instdir_SQ)' && $(TAR) xf -) From 4c8f8c86e11caa7a1cb1c035a9181ed31ffb253e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 12 Jan 2008 20:42:55 +0100 Subject: [PATCH 0364/3720] gitk: Disable msgfmt on MinGW. This auto-detects whether the build takes place for the MinGW port, which does not have msgfmt. Signed-off-by: Johannes Sixt --- gitk-git/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gitk-git/Makefile b/gitk-git/Makefile index ae2b80b108..a25e5a12a1 100644 --- a/gitk-git/Makefile +++ b/gitk-git/Makefile @@ -18,6 +18,10 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) ## po-file creation rules XGETTEXT ?= xgettext +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +ifneq (,$(findstring MINGW,$(uname_S))) + NO_MSGFMT=1 +endif ifdef NO_MSGFMT MSGFMT ?= $(TCL_PATH) po/po2msg.sh else From 9b4b9da619e4bcb25eb581ddb73ff628cc97ac95 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 14 Jan 2008 13:03:34 +0100 Subject: [PATCH 0365/3720] Windows: Fix path separator of GIT_ALTERNATE_OBJECT_DIRECTORIES. For consistency and technical reasons on Windows (':' is usually part of directory names), we must use ';' as path separator. Signed-off-by: Johannes Sixt --- Documentation/git.txt | 6 +++--- sha1_file.c | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index 4ece40d1eb..6e0540d0e6 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -375,9 +375,9 @@ git so take care if using Cogito etc. 'GIT_ALTERNATE_OBJECT_DIRECTORIES':: Due to the immutable nature of git objects, old objects can be archived into shared, read-only directories. This variable - specifies a ":" separated list of git object directories which - can be used to search for git objects. New objects will not be - written to these directories. + specifies a ":" separated (on Windows ";" separated) list + of git object directories which can be used to search for git + objects. New objects will not be written to these directories. 'GIT_DIR':: If the 'GIT_DIR' environment variable is set then it diff --git a/sha1_file.c b/sha1_file.c index 08cebe1fae..93a34271e6 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -395,7 +395,11 @@ void prepare_alt_odb(void) if (!alt) alt = ""; alt_odb_tail = &alt_odb_list; +#ifdef __MINGW32__ + link_alt_odb_entries(alt, alt + strlen(alt), ';', NULL, 0); +#else link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0); +#endif read_info_alternates(get_object_directory(), 0); } From dfd188ababfd634c4cc2a18f6ed38c3829e5058c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 14 Jan 2008 14:05:33 +0100 Subject: [PATCH 0366/3720] Windows: Make 'git help -a' work. git help -a scans the PATH for git commands. On Windows it failed for two reasons: - The PATH separator is ';', not ':' on Windows. - stat() does not set the executabe bit. We now open the file and guess whether it is executable. The result of the guess is good enough for the list of git commands, but it is of no use for a general stat() implementation because (1) it is a guess, (2) the user has no way to influence the outcome (via chmod or similar), and (3) it would reduce stat() performance by an unacceptable amount. Therefore, this strategy is a special-case local to help.c. Signed-off-by: Johannes Sixt --- help.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/help.c b/help.c index 1302a61c83..15a67dec35 100644 --- a/help.c +++ b/help.c @@ -165,6 +165,32 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest) } } +static int is_executable(const char *name) +{ + struct stat st; + + if (stat(name, &st) || /* stat, not lstat */ + !S_ISREG(st.st_mode)) + return 0; + +#ifdef __MINGW32__ + /* cannot trust the executable bit, peek into the file instead */ + char buf[3] = { 0 }; + int n; + int fd = open(name, O_RDONLY); + st.st_mode &= ~S_IXUSR; + if (fd >= 0) { + n = read(fd, buf, 2); + if (n == 2) + /* DOS executables start with "MZ" */ + if (!strcmp(buf, "#!") || !strcmp(buf, "MZ")) + st.st_mode |= S_IXUSR; + close(fd); + } +#endif + return st.st_mode & S_IXUSR; +} + static unsigned int list_commands_in_dir(struct cmdnames *cmds, const char *path) { @@ -178,15 +204,12 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds, return 0; while ((de = readdir(dir)) != NULL) { - struct stat st; int entlen; if (prefixcmp(de->d_name, prefix)) continue; - if (stat(de->d_name, &st) || /* stat, not lstat */ - !S_ISREG(st.st_mode) || - !(st.st_mode & S_IXUSR)) + if (!is_executable(de->d_name)) continue; entlen = strlen(de->d_name) - prefix_len; @@ -210,6 +233,11 @@ static void list_commands(void) const char *env_path = getenv("PATH"); char *paths, *path, *colon; const char *exec_path = git_exec_path(); +#ifdef __MINGW32__ + char sep = ';'; +#else + char sep = ':'; +#endif if (exec_path) longest = list_commands_in_dir(&main_cmds, exec_path); @@ -221,7 +249,7 @@ static void list_commands(void) path = paths = xstrdup(env_path); while (1) { - if ((colon = strchr(path, ':'))) + if ((colon = strchr(path, sep))) *colon = 0; len = list_commands_in_dir(&other_cmds, path); From aeb782846ebff9c3c8abf835ab7406e2a5a685ae Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 29 Jan 2008 06:45:36 +0100 Subject: [PATCH 0367/3720] t5520: Skip '--rebase rebased upstream' on msys (remote doesn't work) We know that git remote does not work in t/. Therefore, we skip this test. Signed-off-by: Steffen Prohaska --- t/t5520-pull.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 9484129ca5..ca83768e05 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -76,6 +76,7 @@ test_expect_success 'branch.to-rebase.rebase' ' test new = $(git show HEAD:file2) ' +say "Remote does not work in t/ - skipping." || test_expect_success '--rebase with rebased upstream' ' git remote add -f me . && From aca4f38d924e0e82f9870babe73c8ada63aadae3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 7 Feb 2008 21:23:32 +0100 Subject: [PATCH 0368/3720] Revert "Implement a cpio emulation in git-merge.sh for Windows." This reverts commit 8b9de093190e6b1d6066efaf4afd9dc988096987. git-merge does not use cpio anymore. --- git-merge.sh | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/git-merge.sh b/git-merge.sh index ca7cb30d6c..1c123a37e6 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -38,24 +38,6 @@ use_strategies= allow_fast_forward=t allow_trivial_merge=t -# Fix some commands on Windows -case $(uname -s) in -*MINGW*) - # there's no cpio; emulate with tar - cpio () { - case "$*" in - "-0 -o") - tar --create --file=- --null --files-from=- - ;; - "-iuv") - tar xvf - - ;; - *) die "internal error: unexpected cpio $*";; - esac - } - ;; -esac - dropsave() { rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \ "$GIT_DIR/MERGE_STASH" || exit 1 From 304601534df0b1eeee0865d55bb3b4da063702e3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 19 Feb 2008 22:11:12 +0100 Subject: [PATCH 0369/3720] prefix_path: use is_absolute_path() instead of *orig == '/' Signed-off-by: Johannes Sixt --- setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.c b/setup.c index 5e4cecb893..18ddfae04f 100644 --- a/setup.c +++ b/setup.c @@ -91,7 +91,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) { const char *orig = path; char *sanitized = xmalloc(len + strlen(path) + 1); - if (*orig == '/') + if (is_absolute_path(orig)) strcpy(sanitized, path); else { if (len) @@ -100,7 +100,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) } if (sanitary_path_copy(sanitized, sanitized)) goto error_out; - if (*orig == '/') { + if (is_absolute_path(orig)) { const char *work_tree = get_git_work_tree(); size_t len = strlen(work_tree); size_t total = strlen(sanitized) + 1; From 6b17197be450fd67d3fde7208bbb1ea0160b73f9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 19 Feb 2008 22:15:17 +0100 Subject: [PATCH 0370/3720] Windows: convert '\\' to '/' in sanitary_path_copy(). sanitary_path_copy() is only used by prefix_path(). A helper function is_dir_sep() is introduced that checks for both '/' and '\\' on Windows. Note that the remaining checks for '/' in prefix_path() don't need to to be converted to is_dir_sep() since they operate on the sanitized path. Signed-off-by: Johannes Sixt --- setup.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/setup.c b/setup.c index 18ddfae04f..b80653c32b 100644 --- a/setup.c +++ b/setup.c @@ -4,13 +4,26 @@ 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 == '\\'; } +#else +static inline int is_dir_sep(char c) { return c == '/'; } +#endif + static int sanitary_path_copy(char *dst, const char *src) { char *dst0 = dst; - if (*src == '/') { +#ifdef __MINGW32__ + if (isalpha(*src) && src[1] == ':') { + src += 2; + dst += 2; + dst0 += 2; + } +#endif + if (is_dir_sep(*src)) { *dst++ = '/'; - while (*src == '/') + while (is_dir_sep(*src)) src++; } @@ -32,9 +45,12 @@ static int sanitary_path_copy(char *dst, const char *src) src++; break; case '/': +#ifdef __MINGW32__ + case '\\': +#endif /* (2) */ src += 2; - while (*src == '/') + while (is_dir_sep(*src)) src++; continue; case '.': @@ -44,9 +60,12 @@ static int sanitary_path_copy(char *dst, const char *src) src += 2; goto up_one; case '/': +#ifdef __MINGW32__ + case '\\': +#endif /* (4) */ src += 3; - while (*src == '/') + while (is_dir_sep(*src)) src++; goto up_one; } @@ -54,11 +73,11 @@ static int sanitary_path_copy(char *dst, const char *src) } /* copy up to the next '/', and eat all '/' */ - while ((c = *src++) != '\0' && c != '/') + while ((c = *src++) != '\0' && !is_dir_sep(c)) *dst++ = c; - if (c == '/') { - *dst++ = c; - while (c == '/') + if (is_dir_sep(c)) { + *dst++ = '/'; + while (is_dir_sep(c)) c = *src++; src--; } else if (!c) @@ -77,7 +96,7 @@ static int sanitary_path_copy(char *dst, const char *src) if (dst <= dst0) break; c = *dst--; - if (c == '/') { + if (c == '/') { /* MinGW: cannot be '\\' anymore */ dst += 2; break; } From a0e491d36a4bf1c19b68be90d82f79a3da95b2f0 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 24 Feb 2008 16:01:14 +0100 Subject: [PATCH 0371/3720] Makefile(msysgit): Do no longer set symlinks=false during installation We track /etc/gitconfig in msysgit and therefore do no longer need to set symlinks=false during installation. This commit removes the unnecessary command from the install target and thus reduces the differences to official git's Makefile. Signed-off-by: Steffen Prohaska --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index 1272b474b4..1b6081782d 100644 --- a/Makefile +++ b/Makefile @@ -1111,8 +1111,6 @@ install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)' - GIT_CONFIG='$(DESTDIR_SQ)$(sysconfdir_SQ)/gitconfig' \ - $(DESTDIR_SQ)$(bindir_SQ)/git$X config core.symlinks false $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install ifndef NO_TCLTK From dbe5a3424bb8ff239b896ab0e888ef402dffa915 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 24 Feb 2008 17:01:54 +0100 Subject: [PATCH 0372/3720] Skip t9500 because we do not support gitweb in msysgit. Signed-off-by: Steffen Prohaska --- t/t9500-gitweb-standalone-no-errors.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 796cd7dba0..72d8e74927 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -68,6 +68,9 @@ safe_chmod () { . ./test-lib.sh +say 'gitweb not supported, skipping tests.' +test_done + perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { test_expect_success 'skipping gitweb tests, perl version is too old' : test_done From d4af30b7c7a9060246fe9d77a9747ed5fa99653b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 24 Feb 2008 17:35:39 +0100 Subject: [PATCH 0373/3720] Fix sanitary_path_copy() for absolute Windows style paths. We recognized the drive letter and colon, but we did not copy them. So far this was not a problem since the only call site used the same pointer for source and destination. But better safe than sorry. Signed-off-by: Johannes Sixt --- setup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.c b/setup.c index b80653c32b..77cc461bd2 100644 --- a/setup.c +++ b/setup.c @@ -16,9 +16,9 @@ static int sanitary_path_copy(char *dst, const char *src) #ifdef __MINGW32__ if (isalpha(*src) && src[1] == ':') { - src += 2; - dst += 2; - dst0 += 2; + *dst++ = *src++; + *dst++ = *src++; + dst0 = dst; } #endif if (is_dir_sep(*src)) { From 792d7e9b0ef778c33d7b1f58d85c17eb7da24a3c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Feb 2008 10:42:01 +0100 Subject: [PATCH 0374/3720] A bit of comment and whitespace cleanup in compat/mingw.c. Signed-off-by: Johannes Sixt --- compat/mingw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8bbe21bb67..0888288b5c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -315,12 +315,14 @@ repeat: struct tm *gmtime_r(const time_t *timep, struct tm *result) { + /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */ memcpy(result, gmtime(timep), sizeof(struct tm)); return result; } struct tm *localtime_r(const time_t *timep, struct tm *result) { + /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */ memcpy(result, localtime(timep), sizeof(struct tm)); return result; } @@ -778,7 +780,7 @@ char **env_setenv(char **env, const char *name) } /* this is the first function to call into WS_32; initialize it */ -#undef gethostbyname +#undef gethostbyname struct hostent *mingw_gethostbyname(const char *host) { WSADATA wsa; @@ -911,7 +913,7 @@ static sig_handler_t timer_fn = SIG_DFL; * wait state every now and then, namely exactly after timer's interval * length. At these opportunities it calls the signal handler. */ - + static __stdcall unsigned ticktack(void *dummy) { while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { From bdb6d4ec8eaac4d01ace50bd521c79f8d4b2d8d5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Feb 2008 10:42:54 +0100 Subject: [PATCH 0375/3720] Replace head -1 | grep by sed. Signed-off-by: Johannes Sixt --- templates/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/Makefile b/templates/Makefile index 0ed2f35003..eb0870235d 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -34,10 +34,10 @@ boilerplates.made : $(bpsrc) mkdir -p blt/$$dir && \ case "$$boilerplate" in \ *--) ;; \ - *) if head -1 $$boilerplate | grep -q '^#!/'; then \ - cp $$boilerplate blt/$${dst}$(NOEXECTEMPL); \ + *) if test -n "$$(sed -ne '/^#!\//p' -e '1q' < "$$boilerplate")"; then \ + cp "$$boilerplate" "blt/$${dst}$(NOEXECTEMPL)"; \ else \ - cp $$boilerplate blt/$$dst; \ + cp "$$boilerplate" "blt/$$dst"; \ fi ;; \ esac || exit; \ done && \ From 43d0446323028d7879167a2d3a3c71b4ec2b8a90 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Feb 2008 10:43:45 +0100 Subject: [PATCH 0376/3720] Send stderr of commands to the pager. This is a follow-up to 61b80509e3323c262ed5c45d5340cfa278521a71. Signed-off-by: Johannes Sixt --- pager.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pager.c b/pager.c index bcb3d7f69d..3f7f8c123e 100644 --- a/pager.c +++ b/pager.c @@ -34,7 +34,10 @@ static struct child_process pager_process = { static void wait_for_pager(void) { fflush(stdout); - close(1); /* signals EOF to pager */ + fflush(stderr); + /* signal EOF to pager */ + close(1); + close(2); finish_command(&pager_process); } #endif @@ -99,6 +102,7 @@ void setup_pager(void) /* original process continues, but writes to the pipe */ dup2(pager_process.in, 1); + dup2(pager_process.in, 2); close(pager_process.in); /* this makes sure that the parent terminates after the pager */ From 3031522444582ac57f851986774ca79560acc33b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 2 Mar 2008 21:54:30 +0100 Subject: [PATCH 0377/3720] Introduce has_dos_drive_prefix() and use it. This function tests whether there is a C: style prefix in the argument. It returns always 0 on Unix. With this functions a number of conditionals #ifdef __MINGW32__/#endif can be removed. The getcwd() replacement was simplified: It tried to elide the translation of backslashes to slashes if there was no drive prfix, but this optimization is wrong: We could be looking at an UNC path, which we also want to translate. Signed-off-by: Johannes Sixt --- cache.h | 6 +----- compat/mingw.c | 11 ++++------- connect.c | 8 +------- git-compat-util.h | 12 ++++++++++++ setup.c | 4 +--- sha1_file.c | 4 +--- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/cache.h b/cache.h index e17bb6f4f5..53b4e44873 100644 --- a/cache.h +++ b/cache.h @@ -484,11 +484,7 @@ int safe_create_leading_directories(char *path); char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) { -#ifndef __MINGW32__ - return path[0] == '/'; -#else - return path[0] == '/' || (path[0] && path[1] == ':'); -#endif + return path[0] == '/' || has_dos_drive_prefix(path); } const char *make_absolute_path(const char *path); diff --git a/compat/mingw.c b/compat/mingw.c index 0888288b5c..6733727380 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -330,16 +330,13 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) #undef getcwd char *mingw_getcwd(char *pointer, int len) { + int i; char *ret = getcwd(pointer, len); if (!ret) return ret; - if (pointer[0] != 0 && pointer[1] == ':') { - int i; - for (i = 2; pointer[i]; i++) - /* Thanks, Bill. You'll burn in hell for that. */ - if (pointer[i] == '\\') - pointer[i] = '/'; - } + for (i = 0; pointer[i]; i++) + if (pointer[i] == '\\') + pointer[i] = '/'; return ret; } diff --git a/connect.c b/connect.c index 92a2829f04..8d600c9ddf 100644 --- a/connect.c +++ b/connect.c @@ -528,13 +528,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, end = host; path = strchr(end, c); -#ifdef __MINGW32__ - /* host must have at least 2 chars to catch DOS C:/path */ - if (path && path - end > 1) -#else - if (path) -#endif - { + if (path && !has_dos_drive_prefix(end)) { if (c == ':') { protocol = PROTO_SSH; *path++ = '\0'; diff --git a/git-compat-util.h b/git-compat-util.h index 4a8df8e038..e9fcffd125 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -650,6 +650,18 @@ char **copy_environ(void); void free_environ(char **env); char **env_setenv(char **env, const char *name); +static inline int has_dos_drive_prefix(const char *path) +{ + return isalpha(*path) && path[1] == ':'; +} + +#else /* __MINGW32__ */ + +static inline int has_dos_drive_prefix(const char *path) +{ + return 0; +} + #endif /* __MINGW32__ */ #endif diff --git a/setup.c b/setup.c index e2e2e21d15..d184d4d5e5 100644 --- a/setup.c +++ b/setup.c @@ -397,10 +397,8 @@ const char *setup_git_directory_gently(int *nongit_ok) if (!getcwd(cwd, sizeof(cwd)-1)) die("Unable to read current working directory"); -#ifdef __MINGW32__ - if (cwd[1] == ':') + if (has_dos_drive_prefix(cwd)) minoffset = 2; -#endif /* * Test in the following order (relative to the cwd): diff --git a/sha1_file.c b/sha1_file.c index 0c608492c7..9a7fac9d5b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -85,10 +85,8 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) static inline int offset_1st_component(const char *path) { -#ifdef __MINGW32__ - if (isalpha(path[0]) && path[1] == ':') + if (has_dos_drive_prefix(path)) return 2 + (path[2] == '/'); -#endif return *path == '/'; } From 7e9987da41172f831f2d900f0304f05d0543319a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 2 Mar 2008 21:56:47 +0100 Subject: [PATCH 0378/3720] Fix clone from bundle if the URL is actually an absolute Windows path. This URL was mistaken as an SSH connection. Signed-off-by: Johannes Sixt --- transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/transport.c b/transport.c index 0a5cf0a9c2..74fa9eef28 100644 --- a/transport.c +++ b/transport.c @@ -693,7 +693,8 @@ static int is_local(const char *url) { const char *colon = strchr(url, ':'); const char *slash = strchr(url, '/'); - return !colon || (slash && slash < colon); + return !colon || (slash && slash < colon) || + has_dos_drive_prefix(url); } static int is_file(const char *url) From 74ea7c5841045e5a66715f705748d9f0f275245b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 12:45:26 +0100 Subject: [PATCH 0379/3720] Move MinGW specific code from git-compat-util.h to compat/mingw.h. This was proposed by Dscho, and I agree it makes sense because it really clutters git-compat-util.h. This is the first step of this cleanup and is a mere code move. Signed-off-by: Johannes Sixt --- Makefile | 2 +- compat/mingw.h | 196 +++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 197 +--------------------------------------------- 3 files changed, 198 insertions(+), 197 deletions(-) create mode 100644 compat/mingw.h diff --git a/Makefile b/Makefile index b7627587c1..cb64a43091 100644 --- a/Makefile +++ b/Makefile @@ -308,7 +308,7 @@ LIB_H = \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h ll-merge.h fsck.h \ - pack-revindex.h + pack-revindex.h compat/mingw.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ diff --git a/compat/mingw.h b/compat/mingw.h new file mode 100644 index 0000000000..50973bc193 --- /dev/null +++ b/compat/mingw.h @@ -0,0 +1,196 @@ +#include + +/* + * things that are not available in header files + */ + +typedef int pid_t; +#define hstrerror strerror + +#define S_IFLNK 0120000 /* Symbolic link */ +#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(x) 0 +#define S_IRGRP 0 +#define S_IWGRP 0 +#define S_IXGRP 0 +#define S_ISGID 0 +#define S_IROTH 0 +#define S_IXOTH 0 + +#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ +#define WEXITSTATUS(x) ((x) & 0xff) +#define WIFSIGNALED(x) ((unsigned)(x) > 259) + +#define SIGKILL 0 +#define SIGCHLD 0 +#define SIGPIPE 0 +#define SIGALRM 100 + +#define F_GETFD 1 +#define F_SETFD 2 +#define FD_CLOEXEC 0x1 + +struct passwd { + char *pw_name; + char *pw_gecos; + char *pw_dir; +}; + +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; +#define POLLIN 1 +#define POLLHUP 2 + +typedef void (__cdecl *sig_handler_t)(int); +struct sigaction { + sig_handler_t sa_handler; + unsigned sa_flags; +}; +#define sigemptyset(x) (void)0 +#define SA_RESTART 0 + +struct itimerval { + struct timeval it_value, it_interval; +}; +#define ITIMER_REAL 0 + +/* + * trivial stubs + */ + +static inline int readlink(const char *path, char *buf, size_t bufsiz) +{ errno = ENOSYS; return -1; } +static inline int symlink(const char *oldpath, const char *newpath) +{ errno = ENOSYS; return -1; } +static inline int link(const char *oldpath, const char *newpath) +{ errno = ENOSYS; return -1; } +static inline int fchmod(int fildes, mode_t mode) +{ errno = ENOSYS; return -1; } +static inline int fork(void) +{ errno = ENOSYS; return -1; } +static inline unsigned int alarm(unsigned int seconds) +{ return 0; } +static inline int fsync(int fd) +{ return 0; } +static inline int getppid(void) +{ return 1; } +static inline void sync(void) +{} +static inline int getuid() +{ return 1; } +static inline struct passwd *getpwnam(const char *name) +{ return NULL; } +static inline int fcntl(int fd, int cmd, long arg) +{ + if (cmd == F_GETFD || cmd == F_SETFD) + return 0; + errno = EINVAL; + return -1; +} + +/* + * simple adaptors + */ + +static inline int mingw_mkdir(const char *path, int mode) +{ + return mkdir(path); +} +#define mkdir mingw_mkdir + +static inline int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} +#define unlink mingw_unlink + +static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +{ + if (options == 0) + return _cwait(status, pid, 0); + errno = EINVAL; + return -1; +} + +/* + * implementations of missing functions + */ + +int pipe(int filedes[2]); +unsigned int sleep (unsigned int seconds); +int gettimeofday(struct timeval *tv, void *tz); +int poll(struct pollfd *ufds, unsigned int nfds, int timeout); +struct tm *gmtime_r(const time_t *timep, struct tm *result); +struct tm *localtime_r(const time_t *timep, struct tm *result); +int getpagesize(void); /* defined in MinGW's libgcc.a */ +struct passwd *getpwuid(int uid); +int setitimer(int type, struct itimerval *in, struct itimerval *out); +int sigaction(int sig, struct sigaction *in, struct sigaction *out); + +/* + * replacements of existing functions + */ + +int mingw_open (const char *filename, int oflags, ...); +#define open mingw_open + +char *mingw_getcwd(char *pointer, int len); +#define getcwd mingw_getcwd + +struct hostent *mingw_gethostbyname(const char *host); +#define gethostbyname mingw_gethostbyname + +int mingw_socket(int domain, int type, int protocol); +#define socket mingw_socket + +int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); +#define connect mingw_connect + +int mingw_rename(const char*, const char*); +#define rename mingw_rename + +/* Use mingw_lstat() instead of lstat()/stat() and + * mingw_fstat() instead of fstat() on Windows. + * struct stat is redefined because it lacks the st_blocks member. + */ +struct mingw_stat { + unsigned st_mode; + time_t st_mtime, st_atime, st_ctime; + unsigned st_dev, st_ino, st_uid, st_gid; + size_t st_size; + size_t st_blocks; +}; +int mingw_lstat(const char *file_name, struct mingw_stat *buf); +int mingw_fstat(int fd, struct mingw_stat *buf); +#define fstat mingw_fstat +#define lstat mingw_lstat +#define stat mingw_stat +static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) +{ return mingw_lstat(file_name, buf); } + +int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); +#define vsnprintf mingw_vsnprintf + +pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); +void mingw_execvp(const char *cmd, char *const *argv); +#define execvp mingw_execvp + +static inline unsigned int git_ntohl(unsigned int x) +{ return (unsigned int)ntohl(x); } +#define ntohl git_ntohl + +sig_handler_t mingw_signal(int sig, sig_handler_t handler); +#define signal mingw_signal + +/* + * helpers + */ + +char **copy_environ(void); +void free_environ(char **env); +char **env_setenv(char **env, const char *name); diff --git a/git-compat-util.h b/git-compat-util.h index 2daec68c6c..6d22739eac 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -468,202 +468,7 @@ void git_qsort(void *base, size_t nmemb, size_t size, #ifdef __MINGW32__ -#include - -/* - * things that are not available in header files - */ - -typedef int pid_t; -#define hstrerror strerror - -#define S_IFLNK 0120000 /* Symbolic link */ -#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) -#define S_ISSOCK(x) 0 -#define S_IRGRP 0 -#define S_IWGRP 0 -#define S_IXGRP 0 -#define S_ISGID 0 -#define S_IROTH 0 -#define S_IXOTH 0 - -#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ -#define WEXITSTATUS(x) ((x) & 0xff) -#define WIFSIGNALED(x) ((unsigned)(x) > 259) - -#define SIGKILL 0 -#define SIGCHLD 0 -#define SIGPIPE 0 -#define SIGALRM 100 - -#define F_GETFD 1 -#define F_SETFD 2 -#define FD_CLOEXEC 0x1 - -struct passwd { - char *pw_name; - char *pw_gecos; - char *pw_dir; -}; - -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; -#define POLLIN 1 -#define POLLHUP 2 - -typedef void (__cdecl *sig_handler_t)(int); -struct sigaction { - sig_handler_t sa_handler; - unsigned sa_flags; -}; -#define sigemptyset(x) (void)0 -#define SA_RESTART 0 - -struct itimerval { - struct timeval it_value, it_interval; -}; -#define ITIMER_REAL 0 - -/* - * trivial stubs - */ - -static inline int readlink(const char *path, char *buf, size_t bufsiz) -{ errno = ENOSYS; return -1; } -static inline int symlink(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } -static inline int link(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } -static inline int fchmod(int fildes, mode_t mode) -{ errno = ENOSYS; return -1; } -static inline int fork(void) -{ errno = ENOSYS; return -1; } -static inline unsigned int alarm(unsigned int seconds) -{ return 0; } -static inline int fsync(int fd) -{ return 0; } -static inline int getppid(void) -{ return 1; } -static inline void sync(void) -{} -static inline int getuid() -{ return 1; } -static inline struct passwd *getpwnam(const char *name) -{ return NULL; } -static inline int fcntl(int fd, int cmd, long arg) -{ - if (cmd == F_GETFD || cmd == F_SETFD) - return 0; - errno = EINVAL; - return -1; -} - -/* - * simple adaptors - */ - -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} -#define mkdir mingw_mkdir - -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - -static inline int waitpid(pid_t pid, unsigned *status, unsigned options) -{ - if (options == 0) - return _cwait(status, pid, 0); - errno = EINVAL; - return -1; -} - -/* - * implementations of missing functions - */ - -int pipe(int filedes[2]); -unsigned int sleep (unsigned int seconds); -int gettimeofday(struct timeval *tv, void *tz); -int poll(struct pollfd *ufds, unsigned int nfds, int timeout); -struct tm *gmtime_r(const time_t *timep, struct tm *result); -struct tm *localtime_r(const time_t *timep, struct tm *result); -int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); -int setitimer(int type, struct itimerval *in, struct itimerval *out); -int sigaction(int sig, struct sigaction *in, struct sigaction *out); - -/* - * replacements of existing functions - */ - -int mingw_open (const char *filename, int oflags, ...); -#define open mingw_open - -char *mingw_getcwd(char *pointer, int len); -#define getcwd mingw_getcwd - -struct hostent *mingw_gethostbyname(const char *host); -#define gethostbyname mingw_gethostbyname - -int mingw_socket(int domain, int type, int protocol); -#define socket mingw_socket - -int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); -#define connect mingw_connect - -int mingw_rename(const char*, const char*); -#define rename mingw_rename - -/* Use mingw_lstat() instead of lstat()/stat() and - * mingw_fstat() instead of fstat() on Windows. - * struct stat is redefined because it lacks the st_blocks member. - */ -struct mingw_stat { - unsigned st_mode; - time_t st_mtime, st_atime, st_ctime; - unsigned st_dev, st_ino, st_uid, st_gid; - size_t st_size; - size_t st_blocks; -}; -int mingw_lstat(const char *file_name, struct mingw_stat *buf); -int mingw_fstat(int fd, struct mingw_stat *buf); -#define fstat mingw_fstat -#define lstat mingw_lstat -#define stat mingw_stat -static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) -{ return mingw_lstat(file_name, buf); } - -int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); -#define vsnprintf mingw_vsnprintf - -pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); -void mingw_execvp(const char *cmd, char *const *argv); -#define execvp mingw_execvp - -static inline unsigned int git_ntohl(unsigned int x) -{ return (unsigned int)ntohl(x); } -#define ntohl git_ntohl - -sig_handler_t mingw_signal(int sig, sig_handler_t handler); -#define signal mingw_signal - -/* - * helpers - */ - -char **copy_environ(void); -void free_environ(char **env); -char **env_setenv(char **env, const char *name); +#include "compat/mingw.h" static inline int has_dos_drive_prefix(const char *path) { From 4bb6564bcb3fd7731af67c79ce443a60409b8d17 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 12:49:13 +0100 Subject: [PATCH 0380/3720] Do not abuse $(EXTRA_PROGRAMS). We don't want to compile some programs on Windows. There was already a Makefile variable EXTRA_PROGRAMS, which we used to achieve this. But this is not exactly self-explanatory. So we name the variable POSIX_ONLY_PROGRAMS and reinstate the old EXTRA_PROGRAMS. Signed-off-by: Johannes Sixt --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index cb64a43091..9023eff0bb 100644 --- a/Makefile +++ b/Makefile @@ -268,6 +268,7 @@ PROGRAMS = \ git-upload-pack$X \ git-pack-redundant$X git-var$X \ git-merge-tree$X \ + $(POSIX_ONLY_PROGRAMS) \ $(EXTRA_PROGRAMS) # Empty... @@ -551,7 +552,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease - NO_EXTRA_PROGRAMS = YesPlease + NO_POSIX_ONLY_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o @@ -621,8 +622,8 @@ ifdef ZLIB_PATH endif EXTLIBS += -lz -ifndef NO_EXTRA_PROGRAMS - EXTRA_PROGRAMS += \ +ifndef NO_POSIX_ONLY_PROGRAMS + POSIX_ONLY_PROGRAMS = \ git-daemon$X \ git-imap-send$X endif From 9ce71e6df09e4b215f639083edb28fadd12a1bf3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 12:52:54 +0100 Subject: [PATCH 0381/3720] Remove executable mode from compat/fnmatch.c Signed-off-by: Johannes Sixt --- compat/fnmatch.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 compat/fnmatch.c diff --git a/compat/fnmatch.c b/compat/fnmatch.c old mode 100755 new mode 100644 From e69e2c6838a84ced873e456e4a48c6d36d950a0e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 12:57:19 +0100 Subject: [PATCH 0382/3720] Include compat/mingw.h early in git-compat-util.h. By doing so we can make the rest of git-compat-util.h believe that some functionality is actually available. Signed-off-by: Johannes Sixt --- git-compat-util.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 6d22739eac..73b08397c9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -89,7 +89,10 @@ #include #define _ALL_SOURCE 1 #endif -#endif /* !__MINGW32__ */ +#else /* __MINGW32__ */ +/* pull in Windows compatibility stuff */ +#include "compat/mingw.h" +#endif /* __MINGW32__ */ #ifndef NO_ICONV #include @@ -468,8 +471,6 @@ void git_qsort(void *base, size_t nmemb, size_t size, #ifdef __MINGW32__ -#include "compat/mingw.h" - static inline int has_dos_drive_prefix(const char *path) { return isalpha(*path) && path[1] == ':'; From 9151da6b3bd05c40d25310f3bb4589b5778bfed3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:01:01 +0100 Subject: [PATCH 0383/3720] Move mkstemp and PRIuMAX to compat/mingw.h. Signed-off-by: Johannes Sixt --- compat/mingw.h | 7 +++++++ git-compat-util.h | 16 +++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 50973bc193..64e0ac79e3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -123,6 +123,7 @@ static inline int waitpid(pid_t pid, unsigned *status, unsigned options) int pipe(int filedes[2]); unsigned int sleep (unsigned int seconds); +int mkstemp(char *template); int gettimeofday(struct timeval *tv, void *tz); int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); @@ -187,6 +188,12 @@ static inline unsigned int git_ntohl(unsigned int x) sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +/* + * git specific compatibility + */ + +#define PRIuMAX "I64u" + /* * helpers */ diff --git a/git-compat-util.h b/git-compat-util.h index 73b08397c9..aac06bfefe 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -106,11 +106,7 @@ #endif #ifndef PRIuMAX -#ifndef __MINGW32__ #define PRIuMAX "llu" -#else -#define PRIuMAX "I64u" -#endif #endif #ifdef __GNUC__ @@ -171,9 +167,11 @@ extern int git_munmap(void *start, size_t length); #define pread git_pread extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif -/* Forward decl that will remind us if its twin in cache.h changes. - This function in used in compat/pread.c. But we can't include - cache.h there. */ +/* + * Forward decl that will remind us if its twin in cache.h changes. + * This function is used in compat/pread.c. But we can't include + * cache.h there. + */ extern int read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV @@ -379,10 +377,6 @@ static inline FILE *xfdopen(int fd, const char *mode) return stream; } -#ifdef __MINGW32__ -int mkstemp(char *template); -#endif - static inline int xmkstemp(char *template) { int fd; From 70aa4faf57b62c52e61bc9cd866dd3392bd4db93 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:06:20 +0100 Subject: [PATCH 0384/3720] Define PATH_SEP to ':' or ';' as needed. This reduces the number of conditionals in the code. Signed-off-by: Johannes Sixt --- compat/mingw.h | 1 + exec_cmd.c | 6 +----- git-compat-util.h | 4 ++++ help.c | 7 +------ sha1_file.c | 6 +----- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 64e0ac79e3..93ef42b9cf 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -192,6 +192,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); * git specific compatibility */ +#define PATH_SEP ';' #define PRIuMAX "I64u" /* diff --git a/exec_cmd.c b/exec_cmd.c index 6d2f740949..84db7ee664 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -70,11 +70,7 @@ static void add_path(struct strbuf *out, const char *path) else strbuf_addstr(out, make_absolute_path(path)); -#ifdef __MINGW32__ - strbuf_addch(out, ';'); -#else - strbuf_addch(out, ':'); -#endif + strbuf_addch(out, PATH_SEP); } } diff --git a/git-compat-util.h b/git-compat-util.h index aac06bfefe..4144605725 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -109,6 +109,10 @@ #define PRIuMAX "llu" #endif +#ifndef PATH_SEP +#define PATH_SEP ':' +#endif + #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else diff --git a/help.c b/help.c index 8d83df5466..04ceed8efd 100644 --- a/help.c +++ b/help.c @@ -240,11 +240,6 @@ static unsigned int load_command_list(void) const char *env_path = getenv("PATH"); char *paths, *path, *colon; const char *exec_path = git_exec_path(); -#ifdef __MINGW32__ - char sep = ';'; -#else - char sep = ':'; -#endif if (exec_path) longest = list_commands_in_dir(&main_cmds, exec_path); @@ -256,7 +251,7 @@ static unsigned int load_command_list(void) path = paths = xstrdup(env_path); while (1) { - if ((colon = strchr(path, sep))) + if ((colon = strchr(path, PATH_SEP))) *colon = 0; len = list_commands_in_dir(&other_cmds, path); diff --git a/sha1_file.c b/sha1_file.c index 2192407494..45231593c7 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -394,11 +394,7 @@ void prepare_alt_odb(void) if (!alt) alt = ""; alt_odb_tail = &alt_odb_list; -#ifdef __MINGW32__ - link_alt_odb_entries(alt, alt + strlen(alt), ';', NULL, 0); -#else - link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0); -#endif + link_alt_odb_entries(alt, alt + strlen(alt), PATH_SEP, NULL, 0); read_info_alternates(get_object_directory(), 0); } From 1881ab8876fe580fd04efd559de54388b8cf8346 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:10:54 +0100 Subject: [PATCH 0385/3720] Move the definition of has_dos_drive_prefix to compat/mingw.c This cannot easily be an inline function because it uses isalpha(), which is not yet declared when compat/mingw.c is parsed and so would give a compiler warning. Signed-off-by: Johannes Sixt --- compat/mingw.h | 1 + git-compat-util.h | 20 ++++---------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 93ef42b9cf..bf3843272b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -192,6 +192,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); * git specific compatibility */ +#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 4144605725..08f764ef9e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -113,6 +113,10 @@ #define PATH_SEP ':' #endif +#ifndef has_dos_drive_prefix +#define has_dos_drive_prefix(path) 0 +#endif + #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else @@ -467,20 +471,4 @@ void git_qsort(void *base, size_t nmemb, size_t size, # define FORCE_DIR_SET_GID 0 #endif -#ifdef __MINGW32__ - -static inline int has_dos_drive_prefix(const char *path) -{ - return isalpha(*path) && path[1] == ':'; -} - -#else /* __MINGW32__ */ - -static inline int has_dos_drive_prefix(const char *path) -{ - return 0; -} - -#endif /* __MINGW32__ */ - #endif From a76ef1f443951642616cf313926c6ebd3d7172a7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:12:18 +0100 Subject: [PATCH 0386/3720] Define is_dir_sep conditionally in compat/mingw.h and git-compat-util.h. By doing it there we can reduce yet another bunch of conditionals from setup.c. Signed-off-by: Johannes Sixt --- compat/mingw.h | 1 + git-compat-util.h | 4 ++++ setup.c | 33 +++++++++------------------------ 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index bf3843272b..abac3f2caf 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -193,6 +193,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); */ #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') +#define is_dir_sep(c) ((c) == '/' || (c) == '\\') #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 08f764ef9e..2889146e89 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -117,6 +117,10 @@ #define has_dos_drive_prefix(path) 0 #endif +#ifndef is_dir_sep +#define is_dir_sep(c) ((c) == '/') +#endif + #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else diff --git a/setup.c b/setup.c index 0ee0ae4f31..eea103807f 100644 --- a/setup.c +++ b/setup.c @@ -4,23 +4,16 @@ 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 == '\\'; } -#else -static inline int is_dir_sep(char c) { return c == '/'; } -#endif - static int sanitary_path_copy(char *dst, const char *src) { - char *dst0 = dst; + char *dst0; -#ifdef __MINGW32__ - if (isalpha(*src) && src[1] == ':') { + if (has_dos_drive_prefix(src)) { *dst++ = *src++; *dst++ = *src++; - dst0 = dst; } -#endif + dst0 = dst; + if (is_dir_sep(*src)) { *dst++ = '/'; while (is_dir_sep(*src)) @@ -39,30 +32,22 @@ static int sanitary_path_copy(char *dst, const char *src) * (4) "../" -- strip one, eat slash and continue. */ if (c == '.') { - switch (src[1]) { - case '\0': + if (!src[1]) { /* (1) */ src++; break; - case '/': -#ifdef __MINGW32__ - case '\\': -#endif + } else if (is_dir_sep(src[1])) { /* (2) */ src += 2; while (is_dir_sep(*src)) src++; continue; - case '.': - switch (src[2]) { - case '\0': + } else if (src[1] == '.') { + if (!src[2]) { /* (3) */ src += 2; goto up_one; - case '/': -#ifdef __MINGW32__ - case '\\': -#endif + } else if (is_dir_sep(src[2])) { /* (4) */ src += 3; while (is_dir_sep(*src)) From 13cae476a6ebb4239531b578109b7130d620ae42 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:16:37 +0100 Subject: [PATCH 0387/3720] templates: Mark only hooks as not-executable. Previously all files in the template directory were investigated whether they are scripts. But actually, we only want to disable the hooks, not any other scripts (but currently there are no others anyway). Signed-off-by: Johannes Sixt --- templates/Makefile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/templates/Makefile b/templates/Makefile index 90bb91d6d7..ab2c823ae0 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -34,11 +34,8 @@ boilerplates.made : $(bpsrc) $(INSTALL) -d -m 755 blt/$$dir && \ case "$$boilerplate" in \ *--) ;; \ - *) if test -n "$$(sed -ne '/^#!\//p' -e '1q' < "$$boilerplate")"; then \ - cp -p "$$boilerplate" "blt/$${dst}$(NOEXECTEMPL)"; \ - else \ - cp -p "$$boilerplate" "blt/$$dst"; \ - fi ;; \ + hooks--*) cp -p $$boilerplate blt/$${dst}$(NOEXECTEMPL) ;; \ + *) cp -p $$boilerplate blt/$$dst ;; \ esac || exit; \ done && \ date >$@ From d0e8078ae5fe00e29df772050a2c62fa5845e286 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:17:42 +0100 Subject: [PATCH 0388/3720] Setup stderr before stdout on Windows as well. This implements what ce2cf27adc does on Unix. Signed-off-by: Johannes Sixt --- run-command.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/run-command.c b/run-command.c index aba2bf2c0f..2ce8c2b2f0 100644 --- a/run-command.c +++ b/run-command.c @@ -132,6 +132,14 @@ int start_command(struct child_process *cmd) dup2(cmd->in, 0); } + if (cmd->no_stderr) { + s2 = dup(2); + dup_devnull(2); + } else if (need_err) { + s2 = dup(2); + dup2(fderr[1], 2); + } + if (cmd->no_stdout) { s1 = dup(1); dup_devnull(1); @@ -146,14 +154,6 @@ int start_command(struct child_process *cmd) dup2(cmd->out, 1); } - if (cmd->no_stderr) { - s2 = dup(2); - dup_devnull(2); - } else if (need_err) { - s2 = dup(2); - dup2(fderr[1], 2); - } - if (cmd->dir) die("chdir in start_command() not implemented"); if (cmd->env) { From c9df829f07533c26c41c2faebc0465a788b08aef Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:18:45 +0100 Subject: [PATCH 0389/3720] Use the available vsnprintf replacement instead of rolling our own. But we still have to cater for the strangeness that on Windows the size parameter is the number of characters to write, not the size of the buffer. Signed-off-by: Johannes Sixt --- Makefile | 2 ++ compat/mingw.c | 34 ---------------------------------- compat/mingw.h | 3 --- compat/snprintf.c | 13 +++++++++++-- 4 files changed, 13 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 9023eff0bb..ea59a15989 100644 --- a/Makefile +++ b/Makefile @@ -550,10 +550,12 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease NO_MKDTEMP = YesPlease + SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat + COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 diff --git a/compat/mingw.c b/compat/mingw.c index 6733727380..7c8fd0e158 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -847,40 +847,6 @@ int mingw_rename(const char *pold, const char *pnew) return -1; } -#undef vsnprintf -/* Note that the size parameter specifies the available space, i.e. - * includes the trailing NUL byte; but Windows's vsnprintf expects the - * number of characters to write without the trailing NUL. - */ - -/* This is out of line because it uses alloca() behind the scenes, - * which must not be called in a loop (alloca() reclaims the allocations - * only at function exit). - */ -static int try_vsnprintf(size_t size, const char *fmt, va_list args) -{ - char buf[size]; /* gcc-ism */ - return vsnprintf(buf, size-1, fmt, args); -} - -int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - int len; - if (size > 0) { - len = vsnprintf(buf, size-1, fmt, args); - if (len >= 0) - return len; - } - /* ouch, buffer too small; need to compute the size */ - if (size < 250) - size = 250; - do { - size *= 4; - len = try_vsnprintf(size, fmt, args); - } while (len < 0); - return len; -} - struct passwd *getpwuid(int uid) { static char user_name[100]; diff --git a/compat/mingw.h b/compat/mingw.h index abac3f2caf..c7db345d58 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -174,9 +174,6 @@ int mingw_fstat(int fd, struct mingw_stat *buf); static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) { return mingw_lstat(file_name, buf); } -int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); -#define vsnprintf mingw_vsnprintf - pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp diff --git a/compat/snprintf.c b/compat/snprintf.c index dbfc2d6b6e..480b66f94e 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -1,12 +1,21 @@ #include "../git-compat-util.h" +/* + * The size parameter specifies the available space, i.e. includes + * the trailing NUL byte; but Windows's vsnprintf expects the + * number of characters to write without the trailing NUL. + */ +#ifndef SNPRINTF_SIZE_CORR +#define SNPRINTF_SIZE_CORR 0 +#endif + #undef vsnprintf int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { char *s; int ret; - ret = vsnprintf(str, maxsize, format, ap); + ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); if (ret != -1) return ret; @@ -20,7 +29,7 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) if (! str) break; s = str; - ret = vsnprintf(str, maxsize, format, ap); + ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); } free(s); return ret; From 2fa62b7f9d40cdd1d617410cab3597f3dac9ddd0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 16 Mar 2008 20:42:55 +0100 Subject: [PATCH 0390/3720] Fix compile error due to utime.h being in a conditional section. Signed-off-by: Johannes Sixt --- git-compat-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-compat-util.h b/git-compat-util.h index af39f009da..0482fcc1c6 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -66,12 +66,12 @@ #include #include #include +#include #ifndef __MINGW32__ #include #include #include #include -#include #ifndef NO_SYS_SELECT_H #include #endif From 239cf481835368d6aa1a9af9a22980f18ded7e1a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 16 Mar 2008 21:22:01 +0100 Subject: [PATCH 0391/3720] t7401-submodule-summary: Use test_cmp instead of plain diff Signed-off-by: Johannes Sixt --- t/t7401-submodule-summary.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 0f3c42ab35..86ed2a2a2d 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -37,7 +37,7 @@ head1=$(add_file sm1 foo1 foo2) test_expect_success 'added submodule' " git add sm1 && git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 0000000...$head1 (2): > Add foo2 @@ -49,7 +49,7 @@ head2=$(add_file sm1 foo3) test_expect_success 'modified submodule(forward)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head1...$head2 (1): > Add foo3 @@ -64,7 +64,7 @@ cd .. test_expect_success 'modified submodule(backward)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head2...$head3 (2): < Add foo3 < Add foo2 @@ -76,7 +76,7 @@ head4=$(add_file sm1 foo4 foo5) && head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD) test_expect_success 'modified submodule(backward and forward)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head2...$head4 (4): > Add foo5 > Add foo4 @@ -88,7 +88,7 @@ EOF test_expect_success '--summary-limit' " git submodule summary -n 3 >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head2...$head4 (4): > Add foo5 > Add foo4 @@ -107,7 +107,7 @@ mv sm1-bak sm1 test_expect_success 'typechanged submodule(submodule->blob), --cached' " git submodule summary --cached >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head4(submodule)->$head5(blob) (3): < Add foo5 @@ -118,7 +118,7 @@ rm -rf sm1 && git checkout-index sm1 test_expect_success 'typechanged submodule(submodule->blob)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head4(submodule)->$head5(blob): EOF @@ -129,7 +129,7 @@ test_create_repo sm1 && head6=$(add_file sm1 foo6 foo7) test_expect_success 'nonexistent commit' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head4...$head6: Warn: sm1 doesn't contain commit $head4_full @@ -139,7 +139,7 @@ EOF commit_file test_expect_success 'typechanged submodule(blob->submodule)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head5(blob)->$head6(submodule) (2): > Add foo7 @@ -150,7 +150,7 @@ commit_file sm1 && rm -rf sm1 test_expect_success 'deleted submodule' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head6...0000000: EOF @@ -162,7 +162,7 @@ git add sm2 test_expect_success 'multiple submodules' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head6...0000000: * sm2 0000000...$head7 (2): @@ -173,7 +173,7 @@ EOF test_expect_success 'path filter' " git submodule summary sm2 >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm2 0000000...$head7 (2): > Add foo9 @@ -183,7 +183,7 @@ EOF commit_file sm2 test_expect_success 'given commit' " git submodule summary HEAD^ >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head6...0000000: * sm2 0000000...$head7 (2): From 3400af9e38925a8ae3a9c619c542e55d258b6f3c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 1 Jan 2008 12:54:28 +0100 Subject: [PATCH 0392/3720] Revert "Added is_dev_null check because Windows /dev/null is nul." This reverts commit 3d9012418c93b5e5f0ada041e1fc071cac48cbfa, which is no longer needed as discussed in http://article.gmane.org/gmane.comp.version-control.msysgit/1134 From Mike Pape's mail: The problem was test t4116-apply-reverse was failing because /dev/null was passed to git diff. This gets converted to nul on Windows, so I added the patch to test for this. However, it looks like Hannes just changed the test in 1f25f36fec4dd895cc6fb73e9cfdecb41e34d155 to not use /dev/null. Not sure if there are other patches that deal with the /dev/null -> nul issue (or if it's even an issue). Conflicts: cache.h Signed-off-by: Steffen Prohaska --- builtin-apply.c | 8 ++++---- cache.h | 9 --------- diff-lib.c | 6 +----- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index ac12628f31..a3f075df4b 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -285,7 +285,7 @@ static unsigned long linelen(const char *buffer, unsigned long size) return len; } -static int is_dev_null_line(const char *str) +static int is_dev_null(const char *str) { return !memcmp("/dev/null", str, 9) && isspace(str[9]); } @@ -392,7 +392,7 @@ static int guess_p_value(const char *nameline) char *name, *cp; int val = -1; - if (is_dev_null_line(nameline)) + if (is_dev_null(nameline)) return -1; name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB); if (!name) @@ -440,12 +440,12 @@ static void parse_traditional_patch(const char *first, const char *second, struc p_value_known = 1; } } - if (is_dev_null_line(first)) { + if (is_dev_null(first)) { patch->is_new = 1; patch->is_delete = 0; name = find_name(second, NULL, p_value, TERM_SPACE | TERM_TAB); patch->new_name = name; - } else if (is_dev_null_line(second)) { + } else if (is_dev_null(second)) { patch->is_new = 0; patch->is_delete = 1; name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB); diff --git a/cache.h b/cache.h index 1b48cfbece..b169900431 100644 --- a/cache.h +++ b/cache.h @@ -487,15 +487,6 @@ static inline int is_absolute_path(const char *path) { return path[0] == '/' || has_dos_drive_prefix(path); } - -static inline int is_dev_null(const char *str) -{ -#ifdef __MINGW32__ - if (!strcmp(str, "nul")) - return 1; -#endif - return !strcmp(str, "/dev/null"); -} const char *make_absolute_path(const char *path); /* Convert slashes in place. On Windows to backslashes. */ char *make_native_separator(char *path); diff --git a/diff-lib.c b/diff-lib.c index 3b0a6c4351..52dbac34a4 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -35,7 +35,7 @@ static int get_mode(const char *path, int *mode) { struct stat st; - if (!path || is_dev_null(path)) + if (!path || !strcmp(path, "/dev/null")) *mode = 0; else if (!strcmp(path, "-")) *mode = create_ce_mode(0666); @@ -234,10 +234,6 @@ static int is_outside_repo(const char *path, int nongit, const char *prefix) int i; if (nongit || !strcmp(path, "-") || is_absolute_path(path)) return 1; -#ifdef __MINGW32__ - if (!strcmp(path, "nul")) - return 1; -#endif if (prefixcmp(path, "../")) return 0; if (!prefix) From 997c13c3898451e1299f0ef2da8b457b1902f2c6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 1 Jan 2008 14:39:06 +0100 Subject: [PATCH 0393/3720] Revert "Provide git_exit() for MinGW" This reverts commit 194c1dbb5a04e29937b87d477a16927fa2c3be62. Instead of mapping exit values < 0 to 1, the original exit code should be fixed. For example, commit 2488df84a28b5eaae5495a59e390b51874d60a03 fixes this for run_command. All tests still pass after this revert. The git_exit() workaround seems no longer necessary. Signed-off-by: Steffen Prohaska --- compat/mingw.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ff2fc832d3..7c8fd0e158 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -979,12 +979,3 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler) timer_fn = handler; return old; } - -#undef exit -int git_exit(int code) -{ - if (code < 0) - exit(1); - exit(code); -} - From 9ef5c15d66da91360eeca7e89d512a6b506f6d57 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 1 Jan 2008 20:31:30 +0100 Subject: [PATCH 0394/3720] Revert replacing getenv() with get_git_dir() This partially reverts commit 855f254b2b5b083a63fc8d7709a42e2cbdc5a136. All tests still pass after this revert. The original commit seems unnecessary. Signed-off-by: Steffen Prohaska --- builtin-init-db.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index 6c46af9228..79eaf8d6ed 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -367,7 +367,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) /* * Set up the default .git directory contents */ - git_dir = get_git_dir(); + git_dir = getenv(GIT_DIR_ENVIRONMENT); + if (!git_dir) + git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; safe_create_dir(git_dir, 0); /* Check to see if the repository version is right. From 24fcae02c33ca0fb05b088d55d12bf97fa2c23f3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 1 Jan 2008 20:34:52 +0100 Subject: [PATCH 0395/3720] Revert replacing setenv() with set_git_dir() This partially reverts commit 855f254b2b5b083a63fc8d7709a42e2cbdc5a136. All tests still pass after this revert. The original commit seems unnecessary. Signed-off-by: Steffen Prohaska --- git.c | 6 +++--- path.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/git.c b/git.c index 5ae18e926f..327215cc91 100644 --- a/git.c +++ b/git.c @@ -45,14 +45,14 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) fprintf(stderr, "No directory given for --git-dir.\n" ); usage(git_usage_string); } - set_git_dir( (*argv)[1] ); + setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1); if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; handled++; } else if (!prefixcmp(cmd, "--git-dir=")) { - set_git_dir(cmd + 10); + setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { @@ -72,7 +72,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) } else if (!strcmp(cmd, "--bare")) { static char git_dir[PATH_MAX+1]; is_bare_repository_cfg = 1; - set_git_dir(getcwd(git_dir, sizeof(git_dir))); + setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0); if (envchanged) *envchanged = 1; } else { diff --git a/path.c b/path.c index 4e19c4cdaa..fe0361aab4 100644 --- a/path.c +++ b/path.c @@ -255,7 +255,7 @@ char *enter_repo(char *path, int strict) if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 && validate_headref("HEAD") == 0) { - set_git_dir("."); + setenv(GIT_DIR_ENVIRONMENT, ".", 1); check_repository_format(); return path; } From 96ddc42f70dd1b080c51af5a50929f2b5811e415 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 30 Dec 2007 16:04:05 +0100 Subject: [PATCH 0396/3720] Revert "Hardlinks are not supported in MSys so we disable them." This reverts commit d1f83218dce62affd1d7a82a9e654cca08dade9c. Hardlinks are supported by MSYS (on NTFS). Conflicts: Makefile git-clone.sh t/Makefile t/test-lib.sh Signed-off-by: Steffen Prohaska --- Makefile | 10 +--------- git-clone.sh | 4 +--- t/Makefile | 4 ---- t/t5701-clone-local.sh | 11 ----------- t/test-lib.sh | 2 -- 5 files changed, 2 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 095e820415..fa5956736c 100644 --- a/Makefile +++ b/Makefile @@ -54,9 +54,6 @@ all:: # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link. # Enable it on Windows. By default, symrefs are still used. # -# Define NO_HARDLINKS if you want to disable hard linking in git clone. -# Enable it on Windows. -# # Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability # tests. These tests take up a significant amount of the total test time # but are not needed unless you plan to talk to SVN repos. @@ -544,7 +541,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_SYMLINK_HEAD = YesPlease - NO_HARDLINKS = YesPlease NO_IPV6 = YesPlease NO_SETENV = YesPlease NO_UNSETENV = YesPlease @@ -841,10 +837,6 @@ ifdef ASCIIDOC8 export ASCIIDOC8 endif -ifdef NO_HARDLINKS - export NO_HARDLINKS -endif - # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@ -923,7 +915,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - -e 's/@@NO_HARDLINKS@@/$(NO_HARDLINKS)/g' \ + -e 's|@@HTMLDIR@@|$(htmldir_SQ)|g' \ $@.sh >$@+ && \ chmod +x $@+ && \ mv $@+ $@ diff --git a/git-clone.sh b/git-clone.sh index edfa1529bc..b783de4300 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -176,7 +176,7 @@ origin_override= use_separate_remote=t depth= no_progress= -test "@@NO_HARDLINKS@@" && use_local_hardlink=no +local_explicitly_asked_for= test -t 1 || no_progress=--no-progress while test $# != 0 @@ -188,8 +188,6 @@ do bare=yes ;; -l|--local) local_explicitly_asked_for=yes - (test "@@NO_HARDLINKS@@" && - echo >&2 "Warning: -l asked but hardlinks are not supported") || use_local_hardlink=yes ;; --no-hardlinks) diff --git a/t/Makefile b/t/Makefile index 4f884466dd..72d7884232 100644 --- a/t/Makefile +++ b/t/Makefile @@ -14,10 +14,6 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) TSVN = $(wildcard t91[0-9][0-9]-*.sh) -ifdef NO_HARDLINKS - GIT_TEST_OPTS += --no-hardlinks -endif - all: $(T) clean $(T): diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index 0bf36a67a0..8dfaaa456e 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -3,13 +3,6 @@ test_description='test local clone' . ./test-lib.sh -if test "$no_hardlinks" -then - say 'Hard links not supported, skipping tests.' - test_done - exit -fi - D=`pwd` test_expect_success 'preparing origin repository' ' @@ -66,10 +59,6 @@ test_expect_success 'With -no-hardlinks, local will make a copy' ' test 0 = $linked ' -say "hardlinks not supported, skipping tests." -test_done -exit 0 - test_expect_success 'Even without -l, local will make a hardlink' ' cd "$D" && rm -fr w && diff --git a/t/test-lib.sh b/t/test-lib.sh index fc4a45323e..0815190a2f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -91,8 +91,6 @@ do --no-python) # noop now... shift ;; - --no-hardlinks) - no_hardlinks=t; shift ;; *) break ;; esac From 46a2df8d4fec1798bb807bf14c28f398d606219b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 18 Mar 2008 09:05:17 +0100 Subject: [PATCH 0397/3720] Skip t6031 if executable bit does not work. Signed-off-by: Johannes Sixt --- t/t6031-merge-recursive.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index c8310aee4f..a8ce5569cb 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -3,6 +3,11 @@ test_description='merge-recursive: handle file mode' . ./test-lib.sh +if test "$(git config --bool core.filemode)" = false; then + say "executable bit not honored - skipping tests" + test_done +fi + test_expect_success 'mode change in one branch: keep changed version' ' : >file1 && git add file1 && From 49133c8b09736ea681d6bcfd31ffecf915137698 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 18 Mar 2008 09:09:52 +0100 Subject: [PATCH 0398/3720] t4150 is broken on Windows. git-am does not recognize Windows style absolute path names. Signed-off-by: Johannes Sixt --- t/t4150-am-subdir.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t4150-am-subdir.sh b/t/t4150-am-subdir.sh index 52069b469b..3cb7965644 100755 --- a/t/t4150-am-subdir.sh +++ b/t/t4150-am-subdir.sh @@ -56,7 +56,11 @@ test_expect_success 'am regularly from file in subdirectory' ' test_cmp expect actual ' -test_expect_success 'am regularly from file in subdirectory with full path' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'am regularly from file in subdirectory with full path' ' rm -fr subdir && git checkout initial && P=$(pwd) && From 04d11973432ed449c196d6f2cc02177f51e01824 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 18 Mar 2008 09:18:53 +0100 Subject: [PATCH 0399/3720] Move the utime() wrapper from test-chmtime.c to mingw.c. The recent commit f746bae84e4746a861d9ebed29fd9255e5cd929f uses utime() to adjust time stamps of pack files. We better make sure that we have an implementation of utime that sets time stamps in a fashion that works with our stat() implementation. (The system's utime() implemenation has issues with daylight saving time changes.) Signed-off-by: Johannes Sixt --- compat/mingw.c | 27 +++++++++++++++++++++++++++ compat/mingw.h | 3 +++ test-chmtime.c | 32 -------------------------------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 7c8fd0e158..a5b43bcf6f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,6 +175,33 @@ int mingw_fstat(int fd, struct mingw_stat *buf) return -1; } +static inline void time_t_to_filetime(time_t t, FILETIME *ft) +{ + long long winTime = t * 10000000LL + 116444736000000000LL; + ft->dwLowDateTime = winTime; + ft->dwHighDateTime = winTime >> 32; +} + +int mingw_utime (const char *file_name, const struct utimbuf *times) +{ + FILETIME mft, aft; + int fh, rc; + + /* must have write permission */ + if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) + return -1; + + time_t_to_filetime(times->modtime, &mft); + time_t_to_filetime(times->actime, &aft); + if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { + errno = EINVAL; + rc = -1; + } else + rc = 0; + close(fh); + return rc; +} + unsigned int sleep (unsigned int seconds) { Sleep(seconds*1000); diff --git a/compat/mingw.h b/compat/mingw.h index c7db345d58..0e18b78b14 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -174,6 +174,9 @@ int mingw_fstat(int fd, struct mingw_stat *buf); static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) { return mingw_lstat(file_name, buf); } +int mingw_utime(const char *file_name, const struct utimbuf *times); +#define utime mingw_utime + pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp diff --git a/test-chmtime.c b/test-chmtime.c index 8a1e6b8479..90da448ebe 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -3,38 +3,6 @@ static const char usage_str[] = "(+|=|=+|=-|-) ..."; -#ifdef __MINGW32__ -static inline void time_t_to_filetime(time_t t, FILETIME *ft) -{ - long long winTime = t * 10000000LL + 116444736000000000LL; - ft->dwLowDateTime = winTime; - ft->dwHighDateTime = winTime >> 32; -} - -int git_utime (const char *file_name, const struct utimbuf *times) -{ - FILETIME mft, aft; - int fh, rc; - - /* must have write permission */ - if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) - return -1; - - time_t_to_filetime(times->modtime, &mft); - time_t_to_filetime(times->actime, &aft); - if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { - errno = EINVAL; - rc = -1; - } else - rc = 0; - close(fh); - return rc; -} - -int git_utime(const char *file_name, const struct utimbuf *times); -#define utime git_utime -#endif /* __MINGW32__ */ - int main(int argc, const char *argv[]) { int i; From 75de7fcca12a911449c966c1dfb7dfc47a23cbaa Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 19 Mar 2008 12:57:59 +0100 Subject: [PATCH 0400/3720] t1004: Exclude tests that involve symbolic links. Signed-off-by: Johannes Sixt --- t/t1004-read-tree-m-u-wf.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh index 570d3729bd..bc6dc95e9c 100755 --- a/t/t1004-read-tree-m-u-wf.sh +++ b/t/t1004-read-tree-m-u-wf.sh @@ -157,6 +157,7 @@ test_expect_success '3-way not overwriting local changes (their side)' ' ' +test "$no_symlinks" || { test_expect_success 'funny symlink in work tree' ' git reset --hard && @@ -191,6 +192,7 @@ test_expect_success 'funny symlink in work tree, un-unlink-able' ' # clean-up from the above test chmod a+w a rm -fr a b +} # $no_symlinks test_expect_success 'D/F setup' ' From f32edf6b14ae405b9e7a4842f18990de6bb4a322 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 28 Mar 2008 16:00:17 +0100 Subject: [PATCH 0401/3720] snprintf replacement: Make sure the result is NUL terminated. On Windows, if the resulting string fits exactly in the provided buffer, but not the terminating NUL, then the return value of the system's vsnprintf is the number of characters written. But since we had reserved an extra byte anyway, we only need to make sure that the result is NUL terminated. Signed-off-by: Johannes Sixt --- compat/snprintf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index 480b66f94e..bddfa5cdde 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -16,8 +16,11 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) int ret; ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); - if (ret != -1) + if (ret != -1) { + /* Windows does not NUL-terminate if result fits exactly */ + str[ret] = 0; return ret; + } s = NULL; if (maxsize < 128) From c1241918459260db1f02eec2dcf27d5002cead43 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 3 Apr 2008 10:14:35 +0200 Subject: [PATCH 0402/3720] Another fix to allow tests on symlink challenged file systems to pass Signed-off-by: Johannes Sixt --- t/t2201-add-update-typechange.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh index e15e3eb81b..69ac97e648 100755 --- a/t/t2201-add-update-typechange.sh +++ b/t/t2201-add-update-typechange.sh @@ -4,6 +4,15 @@ test_description='more git add -u' . ./test-lib.sh +symlink_change=T +if test "$no_symlinks" +then + ln () { + echo -n "$2" > "$3" + } + symlink_change=M +fi + _z40=0000000000000000000000000000000000000000 test_expect_success setup ' @@ -71,7 +80,7 @@ test_expect_success modify ' s/blob/000000/ } / nitfol/{ - s/ nitfol/ $_z40 T&/ + s/ nitfol/ $_z40 $symlink_change&/ s/blob/100644/ } / rezrov.bozbar/{ From 0c75c2ff5c78ae7fcba2bc1a5928c7aa2d522986 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:21:54 +0200 Subject: [PATCH 0403/3720] t3903: Mark tests as broken on MinGW MinGW's bash eats curly braces in "git stash drop stash@{1}". This causes two tests in t3903 to fail. Those breakages are marked expected. You can work around the breakage by escaping the curly braces as "git stash drop stash@\\{1\\}". Signed-off-by: Steffen Prohaska --- t/t3903-stash.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 2d3ee3b78c..d717a02b54 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -88,7 +88,11 @@ test_expect_success 'drop top stash' ' test 1 = $(git show HEAD:file) ' -test_expect_success 'drop middle stash' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'drop middle stash' ' git reset --hard && echo 8 > file && git stash && @@ -108,7 +112,7 @@ test_expect_success 'drop middle stash' ' test 1 = $(git show HEAD:file) ' -test_expect_success 'stash pop' ' +$test_expect 'stash pop' ' git reset --hard && git stash pop && test 3 = $(cat file) && From 0b4d5c6b39bb6e3dfeeddc71d1c86c30f25196bd Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:52:29 +0200 Subject: [PATCH 0404/3720] t7201: Mark tests as broken on MinGW MinGW's path conversion mangles ":/". This breakages is marked expected. Unfortunately, the heuristic in msys_p2w() does not allow for a workaround. Signed-off-by: Steffen Prohaska --- t/t7201-co.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 3111baa9e3..5dd79bd018 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -207,7 +207,11 @@ test_expect_success 'checkout to detach HEAD with branchname^' ' fi ' -test_expect_success 'checkout to detach HEAD with :/message' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'checkout to detach HEAD with :/message' ' git checkout -f master && git clean -f && git checkout ":/Initial" && From e1d3b40b7e7addc8adc065c99d7affa7611e2428 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:18:32 +0200 Subject: [PATCH 0405/3720] test-lib: Set is_mingw on MinGW We need to skip some tests on MinGW because they test features that are not available on Windows. This commit adds a shell variable is_mingw. You can test is_mingw to skip a test only on MinGW. Signed-off-by: Steffen Prohaska --- t/test-lib.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 30a181d548..11ef041335 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -438,5 +438,6 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + is_mingw=t ;; esac From e0203e1029f45b506a67a5815065fc78d6c1c078 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:20:46 +0200 Subject: [PATCH 0406/3720] t5503: Skip four tests on MinGW The tests fail on MinGW because GIT_DEBUG_SEND_PACK is not supported. See http://article.gmane.org/gmane.comp.version-control.msysgit/1992 Signed-off-by: Steffen Prohaska --- t/t5503-tagfollow.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 86e5b9bc26..398b13184c 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -41,6 +41,7 @@ cat - <expect want $A #E EOF +test "$is_mingw" || test_expect_success 'fetch A (new commit : 1 connection)' ' rm -f $U ( @@ -71,6 +72,7 @@ want $C want $T #E EOF +test "$is_mingw" || test_expect_success 'fetch C, T (new branch, tag : 1 connection)' ' rm -f $U ( @@ -107,6 +109,7 @@ want $B want $S #E EOF +test "$is_mingw" || test_expect_success 'fetch B, S (commit and tag : 1 connection)' ' rm -f $U ( @@ -127,6 +130,7 @@ want $B want $S #E EOF +test "$is_mingw" || test_expect_success 'new clone fetch master and tags' ' git branch -D cat rm -f $U From 1a14b8acccc659eb63e1e18309c356910b0eed95 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:31:32 +0200 Subject: [PATCH 0407/3720] t5505: On MinGW, use Windows path in expected output of "git remote show" "git remote show" prints the Windows path. This commit modifies the expected output to also use the Windows path, instead of the Unix path. Signed-off-by: Steffen Prohaska --- t/t5505-remote.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0a7fea865d..ddfa4740ed 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -97,9 +97,13 @@ test_expect_success 'remove remote' ' ) ' +case $(uname -s) in +*MINGW*) PWD="pwd -W";; +*) PWD=pwd;; +esac cat > test/expect << EOF * remote origin - URL: $(pwd)/one/.git + URL: $($PWD)/one/.git Remote branch merged with 'git pull' while on branch master master New remote branch (next fetch will store in remotes/origin) From b4078242a7b03c967c2829205b5461afb82d19b4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:43:44 +0200 Subject: [PATCH 0408/3720] t7401: Tell diff to ignore whitespace on MinGW "git submodule" prints CRLF lineendings, which break the comparison with expected outputs. This commit sets the diff command to ignore whitespace changes. Signed-off-by: Steffen Prohaska --- t/t7401-submodule-summary.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 86ed2a2a2d..f34d8f0bb2 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -8,6 +8,10 @@ test_description='Summary support for submodules This test tries to verify the sanity of summary subcommand of git-submodule. ' +case $(uname -s) in +*MINGW*) GIT_TEST_CMP="diff -uw";; +esac + . ./test-lib.sh add_file () { From 90fba70984a429aa21972932c0775638d15a44d6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 13:48:24 +0200 Subject: [PATCH 0409/3720] t5511: Disable test with "::" on MinGW We must not use arguments with "::" on MinGW. MSYS' path conversion heuristic mangles such arguments. The heuristic considers them path lists and converts ":" to ";". This commit disables a test that uses "::". Signed-off-by: Steffen Prohaska --- t/t5511-refspec.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 670a8f1c99..d061f6a4c2 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -46,6 +46,7 @@ test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' +test "$is_mingw" || test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid From a1fca27d1ee3fd7af09e702a326a8897ee4c0a13 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 19 Apr 2008 11:21:16 +0200 Subject: [PATCH 0410/3720] MinGW: Mark some tests as "still broken" instead of skipping them --- t/t3903-stash.sh | 4 ++++ t/t5503-tagfollow.sh | 29 +++++++++++++++++++++-------- t/t5511-refspec.sh | 12 ++++++++++-- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index d717a02b54..0858aadb87 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -112,6 +112,10 @@ $test_expect 'drop middle stash' ' test 1 = $(git show HEAD:file) ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac $test_expect 'stash pop' ' git reset --hard && git stash pop && diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 398b13184c..f6828281bd 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -41,8 +41,12 @@ cat - <expect want $A #E EOF -test "$is_mingw" || -test_expect_success 'fetch A (new commit : 1 connection)' ' + +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch A (new commit : 1 connection)' ' rm -f $U ( cd cloned && @@ -72,8 +76,11 @@ want $C want $T #E EOF -test "$is_mingw" || -test_expect_success 'fetch C, T (new branch, tag : 1 connection)' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch C, T (new branch, tag : 1 connection)' ' rm -f $U ( cd cloned && @@ -109,8 +116,11 @@ want $B want $S #E EOF -test "$is_mingw" || -test_expect_success 'fetch B, S (commit and tag : 1 connection)' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch B, S (commit and tag : 1 connection)' ' rm -f $U ( cd cloned && @@ -130,8 +140,11 @@ want $B want $S #E EOF -test "$is_mingw" || -test_expect_success 'new clone fetch master and tags' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'new clone fetch master and tags' ' git branch -D cat rm -f $U ( diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index d061f6a4c2..e773b5d7bd 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -4,6 +4,8 @@ test_description='refspec parsing' . ./test-lib.sh +test_expect=test_expect_success + test_refspec () { kind=$1 refspec=$2 expect=$3 @@ -19,7 +21,7 @@ test_refspec () { title="$kind $refspec (invalid)" test='test_must_fail git ls-remote frotz' fi - test_expect_success "$title" "$test" + $test_expect "$title" "$test" } test_refspec push '' invalid @@ -46,8 +48,14 @@ test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' -test "$is_mingw" || + +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid +test_expect=test_expect_success + test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid test_refspec push 'master~1:refs/remotes/frotz/backup' From 6c22598c24c822c6911b272d196e72cda6e79ebf Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Fri, 2 May 2008 09:40:40 +0200 Subject: [PATCH 0411/3720] Revert "test-lib: Set is_mingw on MinGW" This reverts commit e1d3b40b7e7addc8adc065c99d7affa7611e2428. --- t/test-lib.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 11ef041335..30a181d548 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -438,6 +438,5 @@ case $(uname -s) in find () { /usr/bin/find "$@" } - is_mingw=t ;; esac From f3ffa502270e78a3ceac5d249a5569052d0f5624 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:52:29 +0200 Subject: [PATCH 0412/3720] t7201: Mark tests as broken on MinGW MinGW's path conversion mangles ":/". This breakages is marked expected. Unfortunately, the heuristic in msys_p2w() does not allow for a workaround. Signed-off-by: Steffen Prohaska --- t/t7201-co.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 3111baa9e3..5dd79bd018 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -207,7 +207,11 @@ test_expect_success 'checkout to detach HEAD with branchname^' ' fi ' -test_expect_success 'checkout to detach HEAD with :/message' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'checkout to detach HEAD with :/message' ' git checkout -f master && git clean -f && git checkout ":/Initial" && From b74e70b3671b129016beb7ad0a241ecc0590d22e Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:31:32 +0200 Subject: [PATCH 0413/3720] t5505: On MinGW, use Windows path in expected output of "git remote show" "git remote show" prints the Windows path. This commit modifies the expected output to also use the Windows path, instead of the Unix path. Signed-off-by: Steffen Prohaska --- t/t5505-remote.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0a7fea865d..ddfa4740ed 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -97,9 +97,13 @@ test_expect_success 'remove remote' ' ) ' +case $(uname -s) in +*MINGW*) PWD="pwd -W";; +*) PWD=pwd;; +esac cat > test/expect << EOF * remote origin - URL: $(pwd)/one/.git + URL: $($PWD)/one/.git Remote branch merged with 'git pull' while on branch master master New remote branch (next fetch will store in remotes/origin) From ab8a9f21c410ebbeab3d94625a13ba738efdbac5 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:43:44 +0200 Subject: [PATCH 0414/3720] t7401: Tell diff to ignore whitespace on MinGW "git submodule" prints CRLF lineendings, which break the comparison with expected outputs. This commit sets the diff command to ignore whitespace changes. Signed-off-by: Steffen Prohaska --- t/t7401-submodule-summary.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 86ed2a2a2d..f34d8f0bb2 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -8,6 +8,10 @@ test_description='Summary support for submodules This test tries to verify the sanity of summary subcommand of git-submodule. ' +case $(uname -s) in +*MINGW*) GIT_TEST_CMP="diff -uw";; +esac + . ./test-lib.sh add_file () { From fe3238dc4c870cb865bd2862f317afeb35018267 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:21:54 +0200 Subject: [PATCH 0415/3720] t3903: Mark tests as broken on MinGW MinGW's bash eats curly braces in "git stash drop stash@{1}". This causes two tests in t3903 to fail. Those breakages are marked expected. You can work around the breakage by escaping the curly braces as "git stash drop stash@\\{1\\}". A check for MINGW is added in front of each test marked, although the first check would be sufficient. Adding the check multiple times, however, allows to remove the checks independently of each other. Signed-off-by: Steffen Prohaska --- t/t3903-stash.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 2d3ee3b78c..0858aadb87 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -88,7 +88,11 @@ test_expect_success 'drop top stash' ' test 1 = $(git show HEAD:file) ' -test_expect_success 'drop middle stash' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'drop middle stash' ' git reset --hard && echo 8 > file && git stash && @@ -108,7 +112,11 @@ test_expect_success 'drop middle stash' ' test 1 = $(git show HEAD:file) ' -test_expect_success 'stash pop' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'stash pop' ' git reset --hard && git stash pop && test 3 = $(cat file) && From f94ce3a59d2c0433282b7c794a2a034a74d6586c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:21:54 +0200 Subject: [PATCH 0416/3720] t5503: Mark tests as broken on MinGW The tests fail on MinGW because GIT_DEBUG_SEND_PACK is not supported. See http://article.gmane.org/gmane.comp.version-control.msysgit/1992 These failures are marked known breakages. A check for MINGW is added in front of each test marked, although the first check would be sufficient. Adding the check multiple times, however, allows to remove the checks independently of each other. Signed-off-by: Steffen Prohaska --- t/t5503-tagfollow.sh | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 86e5b9bc26..f6828281bd 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -41,7 +41,12 @@ cat - <expect want $A #E EOF -test_expect_success 'fetch A (new commit : 1 connection)' ' + +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch A (new commit : 1 connection)' ' rm -f $U ( cd cloned && @@ -71,7 +76,11 @@ want $C want $T #E EOF -test_expect_success 'fetch C, T (new branch, tag : 1 connection)' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch C, T (new branch, tag : 1 connection)' ' rm -f $U ( cd cloned && @@ -107,7 +116,11 @@ want $B want $S #E EOF -test_expect_success 'fetch B, S (commit and tag : 1 connection)' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch B, S (commit and tag : 1 connection)' ' rm -f $U ( cd cloned && @@ -127,7 +140,11 @@ want $B want $S #E EOF -test_expect_success 'new clone fetch master and tags' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'new clone fetch master and tags' ' git branch -D cat rm -f $U ( From ed697a2400d95fc565bdd740e894722d2ae7f35b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:21:54 +0200 Subject: [PATCH 0417/3720] t5511: Mark test with "::" as broken on MinGW We must not use arguments with "::" on MinGW. MSYS' path conversion heuristic mangles such arguments. The heuristic considers them path lists and converts ":" to ";". This commit marks a test that uses "::" as broken. Signed-off-by: Steffen Prohaska --- t/t5511-refspec.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 670a8f1c99..e773b5d7bd 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -4,6 +4,8 @@ test_description='refspec parsing' . ./test-lib.sh +test_expect=test_expect_success + test_refspec () { kind=$1 refspec=$2 expect=$3 @@ -19,7 +21,7 @@ test_refspec () { title="$kind $refspec (invalid)" test='test_must_fail git ls-remote frotz' fi - test_expect_success "$title" "$test" + $test_expect "$title" "$test" } test_refspec push '' invalid @@ -46,7 +48,14 @@ test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' + +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid +test_expect=test_expect_success + test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid test_refspec push 'master~1:refs/remotes/frotz/backup' From e81573e4720b69b109062493b505d01b1c6acb1c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 May 2008 21:43:58 +0200 Subject: [PATCH 0418/3720] Update read_in_full() declaration in git-compat-util.h. Commit 0104ca09e3abf48ab26fd0599c4b686fcff60ffc changed the prototype. Signed-off-by: Johannes Sixt --- git-compat-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-compat-util.h b/git-compat-util.h index 6ae14562b7..11f6c4ab9c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -185,7 +185,7 @@ extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); * This function is used in compat/pread.c. But we can't include * cache.h there. */ -extern int read_in_full(int fd, void *buf, size_t count); +extern ssize_t read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv From 3c81b4476c964cfaa8a3f5dc349d82765e66b060 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Apr 2008 12:07:12 +0200 Subject: [PATCH 0419/3720] Skip more symbolic link tests. Signed-off-by: Johannes Sixt --- t/t4114-apply-typechange.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh index 55334927ab..33c71ad38d 100755 --- a/t/t4114-apply-typechange.sh +++ b/t/t4114-apply-typechange.sh @@ -9,6 +9,11 @@ test_description='git apply should not get confused with type changes. . ./test-lib.sh +test "$no_symlinks" && { + say "Symbolic links not supported - skipping tests" + test_done +} + test_expect_success 'setup repository and commits' ' echo "hello world" > foo && echo "hi planet" > bar && From 60248c8c59512036e93d9dce89a0b7408afc01f9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Apr 2008 12:07:59 +0200 Subject: [PATCH 0420/3720] Use diff -w on Windows to ignore CRLF. Signed-off-by: Johannes Sixt --- t/t7502-status.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7502-status.sh b/t/t7502-status.sh index e4bfcaece0..ededff28ad 100755 --- a/t/t7502-status.sh +++ b/t/t7502-status.sh @@ -5,6 +5,10 @@ test_description='git-status' +case $(uname -s) in +*MINGW*) GIT_TEST_CMP="diff -uw";; +esac + . ./test-lib.sh test_expect_success 'setup' ' From dfd702ef0be17937651e925f8c0367b4b9d3de2f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 27 May 2008 00:15:06 +0100 Subject: [PATCH 0421/3720] Fix t5100 for Windows On Windows, "nul" is not allowed as a file name. So bend over for that platform even more than we do already. Signed-off-by: Johannes Schindelin --- t/t5100-mailinfo.sh | 4 ++-- t/t5100/{nul => nul-plain} | Bin 2 files changed, 2 insertions(+), 2 deletions(-) rename t/t5100/{nul => nul-plain} (100%) diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index a8b78ebf7d..577ecc210a 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -27,8 +27,8 @@ done test_expect_success 'respect NULs' ' - git mailsplit -d3 -o. ../t5100/nul && - cmp ../t5100/nul 001 && + git mailsplit -d3 -o. ../t5100/nul-plain && + cmp ../t5100/nul-plain 001 && (cat 001 | git mailinfo msg patch) && test 4 = $(wc -l < patch) diff --git a/t/t5100/nul b/t/t5100/nul-plain similarity index 100% rename from t/t5100/nul rename to t/t5100/nul-plain From e2829542f8d63138abe19ef638a0845d18695d5b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 27 May 2008 08:55:25 +0200 Subject: [PATCH 0422/3720] Fix reference to $(template_dir) in Makefile. The brackets were missing, so that 'make install' would install into the directory template/emplate_dir. Signed-off-by: Johannes Sixt --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d8edd42a23..3fd53e4e03 100644 --- a/Makefile +++ b/Makefile @@ -1260,7 +1260,7 @@ remove-dashes: ifeq ($(firstword $(subst /, ,$(template_dir))),..) template_instdir = $(gitexecdir)/$(template_dir) else -template_instdir = $template_dir +template_instdir = $(template_dir) endif export template_instdir From 9ea874f89a6a90970364630ed8e80e1909ded409 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 27 May 2008 09:38:07 +0200 Subject: [PATCH 0423/3720] Skip tests that use chmod 0 - it does not make files unreadable on Windows. Signed-off-by: Johannes Sixt --- t/t3700-add.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 79cb00d1e8..55e6425a29 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -183,6 +183,10 @@ test_expect_success 'git add --refresh' ' test -z "`git diff-index HEAD -- foo`" ' +if case $(uname -s) in *MINGW*) :;; *) false;; esac then + say "chmod 0 does not make files unreadable - skipping tests" +else + test_expect_success 'git add should fail atomically upon an unreadable file' ' git reset --hard && date >foo1 && @@ -226,4 +230,6 @@ test_expect_success 'git add (add.ignore-errors = false)' ' ! ( git ls-files foo1 | grep foo1 ) ' +fi # skip chmod 0 tests + test_done From e00e4b2ef41c6622a4afcbdb8dc0725b6f1b459a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 May 2008 21:46:54 +0200 Subject: [PATCH 0424/3720] Skip unwritable object directory tests. chmod a-w does not make a directory unwritable on Windows. Signed-off-by: Johannes Sixt --- t/t0004-unwritable.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh index 9255c63c08..f1385d6ded 100755 --- a/t/t0004-unwritable.sh +++ b/t/t0004-unwritable.sh @@ -4,6 +4,13 @@ test_description='detect unwritable repository and fail correctly' . ./test-lib.sh +case "$(uname -s)" in +*MINGW*) + say "chmod a-w .git/objects does not make directory unwritable - skipping tests" + test_done + ;; +esac + test_expect_success setup ' >file && From df177fba3c2da3e69780b7a56628a8a7a1de024d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Apr 2008 12:15:15 +0200 Subject: [PATCH 0425/3720] t5300-pack-object: Set up the objects for --strict tests only once. The two --strict tests use the exact same sequence to set up the repository. This factores the setup step into a test of its own. Signed-off-by: Johannes Sixt --- t/t5300-pack-object.sh | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 83c67c4a5a..49817f1ce7 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -286,7 +286,7 @@ test_expect_success \ packname_4=$(git pack-objects test-4 LIST && - rm -f .git/index && - git update-index --index-info Date: Mon, 2 Jun 2008 10:14:29 +0200 Subject: [PATCH 0426/3720] Add #defines for SIGHUP and SIGQUIT. Signed-off-by: Johannes Sixt --- compat/mingw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 0e18b78b14..6965e3f2df 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -24,6 +24,8 @@ typedef int pid_t; #define SIGKILL 0 #define SIGCHLD 0 #define SIGPIPE 0 +#define SIGHUP 0 +#define SIGQUIT 0 #define SIGALRM 100 #define F_GETFD 1 From f01c16a4bbb417160dca721aa732b179cd40a98c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 4 Jun 2008 19:29:25 +0200 Subject: [PATCH 0427/3720] Remove the fake 'sync' command. It was added to silence git-repack, but it is no longer used there. Signed-off-by: Johannes Sixt --- git-sh-setup.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 822aa6f83a..9cceb21a82 100755 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -153,9 +153,5 @@ case $(uname -s) in find () { /usr/bin/find "$@" } - # sync is missing - sync () { - : # no implementation - } ;; esac From b1013825f97b4f5a8097c25ee2a3cd4679f38f24 Mon Sep 17 00:00:00 2001 From: raible Date: Sun, 8 Jun 2008 09:51:32 +0200 Subject: [PATCH 0428/3720] mingw: Quote '{}' to work around an error in MSYS' glob() MSYS expands '{}' in paths even if the pattern between the braces does not contain a comma. See http://article.gmane.org/gmane.comp.version-control.msysgit/2341 for a detailed discussion. This commit fixes (at least) the case of "git stash apply stash@{1}". Note that "git-stash apply stash@{1}" works even without this patch (because it is executed directly by /bin/sh). Note that git-stash still has a bug whereby it doesn't validate its final argument ("stash@{1}" in this case). This commit does nothing to fix that problem. Signed-off-by: Steffen Prohaska --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index a5b43bcf6f..95ba563a27 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -380,7 +380,7 @@ static const char *quote_arg(const char *arg) const char *p = arg; if (!*p) force_quotes = 1; while (*p) { - if (isspace(*p) || *p == '*' || *p == '?') + if (isspace(*p) || *p == '*' || *p == '?' || *p == '{') force_quotes = 1; else if (*p == '"') n++; From 54b9e8917c44c456c445dece61389f0478505352 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Thu, 5 Jun 2008 01:49:03 -0400 Subject: [PATCH 0429/3720] connect.c: Fix custom port SSH with PuTTY plink on Windows OpenSSH uses -p to specify custom ports, while PuTTY uses -P. Git should detect if plink is in GIT_SSH and modify its flags as necessary. Also fixed is a possible hang due to faulty stdin forwarding to plink when plink attempts to be interactive. Signed-off-by: Edward Z. Yang Signed-off-by: Steffen Prohaska --- connect.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 574f42fa47..6bd7ec9117 100644 --- a/connect.c +++ b/connect.c @@ -596,14 +596,24 @@ struct child_process *git_connect(int fd[2], const char *url_orig, die("command line too long"); conn->in = conn->out = -1; - conn->argv = arg = xcalloc(6, sizeof(*arg)); + /* be sure to increase this size if you add more args */ + conn->argv = arg = xcalloc(8, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); + int putty = ssh && strstr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; + if (putty) { + /* stdin forwarding doesn't work, so give informative error messages + * (-v) and don't hang (-batch). + */ + *arg++ = "-batch"; + *arg++ = "-v"; + } if (port) { - *arg++ = "-p"; + /* P is for PuTTY, p is for OpenSSH */ + *arg++ = putty ? "-P" : "-p"; *arg++ = port; } *arg++ = host; From 3ad18f2446748cb3b2d21454c01f917315fcd806 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Sun, 2 Mar 2008 16:30:29 -0500 Subject: [PATCH 0430/3720] Scan for \r in addition to \n when reading shbang lines Signed-off-by: Steffen Prohaska --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index a5b43bcf6f..f036b3383c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -448,8 +448,8 @@ static const char *parse_interpreter(const char *cmd) if (buf[0] != '#' || buf[1] != '!') return NULL; buf[n] = '\0'; - p = strchr(buf, '\n'); - if (!p) + p = buf + strcspn(buf, "\r\n"); + if (!*p) return NULL; *p = '\0'; From 3ec8d36fbf055f40bb5639221a260ae9a37d62e0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 11 Jun 2008 15:15:08 +0200 Subject: [PATCH 0431/3720] Fix vsnprintf() emulation again. On Windows, if the native vsnprintf() fills the buffer, it does not add the terminating NUL. The earlier commit f32edf6b tried to fix the emulation, but the fix worked only if the formatted string fitted into the buffer exactly. However, there are callers that do not try to resize the buffer if it overflows, and in these cases the resulting string remained without the trailing NUL. This patch adds the NUL in all cases. Signed-off-by: Johannes Sixt --- compat/snprintf.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index bddfa5cdde..580966e56a 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -13,14 +13,15 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { char *s; - int ret; + int ret = -1; - ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); - if (ret != -1) { - /* Windows does not NUL-terminate if result fits exactly */ - str[ret] = 0; - return ret; + if (maxsize > 0) { + ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); + /* Windows does not NUL-terminate if result fills buffer */ + str[maxsize-1] = 0; } + if (ret != -1) + return ret; s = NULL; if (maxsize < 128) From e77b5a4f7c0d3fef4b0f3d0996baaadf2529b440 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 1 Mar 2008 19:48:40 -0500 Subject: [PATCH 0432/3720] Add ANSI control code emulation for the Windows console This adds only the minimum necessary to keep git pull/merge's diffstat from wrapping. Notably absent is support for the K (erase) operation, and support for POSIX write. Cygwin does not need the WIN_ANSI define, since it has its own (more complete) ANSI emulation. Signed-off-by: Peter Harris --- Makefile | 6 + compat/winansi.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 7 ++ 3 files changed, 322 insertions(+) create mode 100644 compat/winansi.c diff --git a/Makefile b/Makefile index 0248759e9a..ea7f0418a1 100644 --- a/Makefile +++ b/Makefile @@ -695,6 +695,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_R_TO_GCC_LINKER = YesPlease INTERNAL_QSORT = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease + WIN_ANSI = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -940,6 +941,11 @@ ifdef NO_EXTERNAL_GREP BASIC_CFLAGS += -DNO_EXTERNAL_GREP endif +ifdef WIN_ANSI + COMPAT_CFLAGS += -DWIN_ANSI + COMPAT_OBJS += compat/winansi.o +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif diff --git a/compat/winansi.c b/compat/winansi.c new file mode 100644 index 0000000000..86c3fd2db3 --- /dev/null +++ b/compat/winansi.c @@ -0,0 +1,309 @@ +#include +#include "../git-compat-util.h" + +/* + Functions to be wrapped: +*/ +#undef printf +#undef fputs + +/* + ANSI codes to implement: m, K +*/ + +static HANDLE console; +static WORD plain_attr; +static WORD attr; +static int negative; + +static void init(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + static int initialized = 0; + if (initialized) + return; + + console = GetStdHandle(STD_OUTPUT_HANDLE); + if (console == INVALID_HANDLE_VALUE) + console = NULL; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + attr = plain_attr = sbi.wAttributes; + negative = 0; + + initialized = 1; +} + + +#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) + +static void set_console_attr(void) +{ + WORD attributes = attr; + if (negative) { + attributes &= ~FOREGROUND_ALL; + attributes &= ~BACKGROUND_ALL; + + /* This could probably use a bitmask instead of a series of ifs */ + if (attr & FOREGROUND_RED) + attributes |= BACKGROUND_RED; + if (attr & FOREGROUND_GREEN) + attributes |= BACKGROUND_GREEN; + if (attr & FOREGROUND_BLUE) + attributes |= BACKGROUND_BLUE; + + if (attr & BACKGROUND_RED) + attributes |= FOREGROUND_RED; + if (attr & BACKGROUND_GREEN) + attributes |= FOREGROUND_GREEN; + if (attr & BACKGROUND_BLUE) + attributes |= FOREGROUND_BLUE; + } + SetConsoleTextAttribute(console, attributes); +} + +static const char *set_attr(const char *str) +{ + const char *func; + size_t len = strspn(str, "0123456789;"); + func = str + len; + + switch (*func) { + case 'm': + do { + long val = strtol(str, (char **)&str, 10); + switch (val) { + case 0: /* reset */ + attr = plain_attr; + negative = 0; + break; + case 1: /* bold */ + attr |= FOREGROUND_INTENSITY; + break; + case 2: /* faint */ + case 22: /* normal */ + attr &= ~FOREGROUND_INTENSITY; + break; + case 3: /* italic */ + /* Unsupported */ + break; + case 4: /* underline */ + case 21: /* double underline */ + /* Wikipedia says this flag does nothing */ + /* Furthermore, mingw doesn't define this flag + attr |= COMMON_LVB_UNDERSCORE; */ + break; + case 24: /* no underline */ + /* attr &= ~COMMON_LVB_UNDERSCORE; */ + break; + case 5: /* slow blink */ + case 6: /* fast blink */ + /* We don't have blink, but we do have background intensity */ + attr |= BACKGROUND_INTENSITY; + break; + case 25: /* no blink */ + attr &= ~BACKGROUND_INTENSITY; + break; + case 7: /* negative */ + negative = 1; + break; + case 27: /* positive */ + negative = 0; + break; + case 8: /* conceal */ + case 28: /* reveal */ + /* Unsupported */ + break; + case 30: /* Black */ + attr &= ~FOREGROUND_ALL; + break; + case 31: /* Red */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED; + break; + case 32: /* Green */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN; + break; + case 33: /* Yellow */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + case 34: /* Blue */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_BLUE; + break; + case 35: /* Magenta */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + case 36: /* Cyan */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case 37: /* White */ + attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case 38: /* Unknown */ + break; + case 39: /* reset */ + attr &= ~FOREGROUND_ALL; + attr |= (plain_attr & FOREGROUND_ALL); + break; + case 40: /* Black */ + attr &= ~BACKGROUND_ALL; + break; + case 41: /* Red */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED; + break; + case 42: /* Green */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN; + break; + case 43: /* Yellow */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + case 44: /* Blue */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_BLUE; + break; + case 45: /* Magenta */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + case 46: /* Cyan */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case 47: /* White */ + attr |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case 48: /* Unknown */ + break; + case 49: /* reset */ + attr &= ~BACKGROUND_ALL; + attr |= (plain_attr & BACKGROUND_ALL); + break; + default: + /* Unsupported code */ + break; + } + str++; + } while (*(str-1) == ';'); + + set_console_attr(); + break; + case 'K': + /* TODO */ + break; + default: + /* Unsupported code */ + break; + } + + return func + 1; +} + +static int ansi_emulate(const char *str, FILE *stream) +{ + int rv = 0; + const char *pos = str; + + while (*pos) { + pos = strstr(str, "\033["); + if (pos) { + size_t len = pos - str; + + if (len) { + size_t output_len = fwrite(str, 1, len, stream); + rv += output_len; + if (output_len < len) + return rv; + } + + str = pos + 2; + rv += 2; + + fflush(stream); + + pos = set_attr(str); + rv += pos - str; + str = pos; + } else { + rv += strlen(str); + fputs(str, stream); + return rv; + } + } + return rv; +} + +int git_fputs(const char *str, FILE *stream) +{ + int rv; + + init(); + + if (!console) + return fputs(str, stream); + + if (!isatty(fileno(stream))) + return fputs(str, stream); + + rv = ansi_emulate(str, stream); + + if (rv >= 0) + return 0; + else + return EOF; +} + +int git_printf(const char *format, ...) +{ + va_list list; + + char small_buf[256]; + char *buf = small_buf; + int len, rv; + + init(); + + if (!console) + goto abort; + + if (!isatty(fileno(stdout))) + goto abort; + + va_start(list, format); + len = vsnprintf(small_buf, sizeof(small_buf), format, list); + va_end(list); + + if (len > sizeof(small_buf) - 1) { + buf = malloc(len + 1); + if (!buf) + goto abort; + + va_start(list, format); + len = vsnprintf(buf, len + 1, format, list); + va_end(list); + } + + rv = ansi_emulate(buf, stdout); + + if (buf != small_buf) + free(buf); + return rv; + +abort: + va_start(list, format); + rv = vprintf(format, list); + va_end(list); + return rv; +} diff --git a/git-compat-util.h b/git-compat-util.h index 625e5e9c80..b810d710d7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -495,4 +495,11 @@ void git_qsort(void *base, size_t nmemb, size_t size, # define FORCE_DIR_SET_GID 0 #endif +#ifdef WIN_ANSI +extern int git_fputs(const char *str, FILE *stream); +extern int git_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); +#define fputs git_fputs +#define printf(...) git_printf(__VA_ARGS__) +#endif + #endif From 3bff7cd86131f6fd39fa3918bdc2682bbfb74717 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 17 Jun 2008 14:42:25 +0200 Subject: [PATCH 0433/3720] t5505: fix pwd on Windows again The earlier commit b74e70b3 set $PWD to the particular 'pwd' form to use on Windows and *nix platforms. But this is not good for two reasons: $PWD has a predefined meaning to the shell (it influences pwd itself), and all occurrences of 'pwd' must be replaced by $PWD. This new fix now simply replaces 'pwd' by a shell function on Windows only, where we can be reasonably certain that 'bash' is in use, so that the function can call the builtin 'pwd' explicitly. Signed-off-by: Johannes Sixt --- t/t5505-remote.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0c1cd17388..881efabd2b 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -108,12 +108,11 @@ test_expect_success 'remove remote' ' ' case $(uname -s) in -*MINGW*) PWD="pwd -W";; -*) PWD=pwd;; +*MINGW*) pwd() { builtin pwd -W; } ;; esac cat > test/expect << EOF * remote origin - URL: $($PWD)/one/.git + URL: $(pwd)/one/.git Remote branch merged with 'git pull' while on branch master master New remote branch (next fetch will store in remotes/origin) From a58901c9bd2de40f6409a77a3f638106bdffaacd Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Sun, 15 Jun 2008 15:53:57 -0400 Subject: [PATCH 0434/3720] Fix custom ports with plink PuTTY requires -P while OpenSSH requires -p; if plink is detected as GIT_SSH, use the alternate flag. Signed-off-by: Edward Z. Yang Signed-off-by: Steffen Prohaska --- connect.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index 574f42fa47..11fa151eb3 100644 --- a/connect.c +++ b/connect.c @@ -596,14 +596,17 @@ struct child_process *git_connect(int fd[2], const char *url_orig, die("command line too long"); conn->in = conn->out = -1; + /* be sure to increase this size if you add more args */ conn->argv = arg = xcalloc(6, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); + int putty = ssh && strstr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; if (port) { - *arg++ = "-p"; + /* P is for PuTTY, p is for OpenSSH */ + *arg++ = putty ? "-P" : "-p"; *arg++ = port; } *arg++ = host; From 33227548ba69857102b928e373a0e023ee59c7da Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Sun, 15 Jun 2008 15:53:57 -0400 Subject: [PATCH 0435/3720] Fix custom ports with plink (without debugging output) PuTTY requires -P while OpenSSH requires -p; if plink is detected as GIT_SSH, use the alternate flag. [spr: This commit switched off plink's debugging output, which was enabled by the previous commit. ] Signed-off-by: Edward Z. Yang Signed-off-by: Steffen Prohaska --- connect.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/connect.c b/connect.c index 6bd7ec9117..11fa151eb3 100644 --- a/connect.c +++ b/connect.c @@ -597,20 +597,13 @@ struct child_process *git_connect(int fd[2], const char *url_orig, conn->in = conn->out = -1; /* be sure to increase this size if you add more args */ - conn->argv = arg = xcalloc(8, sizeof(*arg)); + conn->argv = arg = xcalloc(6, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); int putty = ssh && strstr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; - if (putty) { - /* stdin forwarding doesn't work, so give informative error messages - * (-v) and don't hang (-batch). - */ - *arg++ = "-batch"; - *arg++ = "-v"; - } if (port) { /* P is for PuTTY, p is for OpenSSH */ *arg++ = putty ? "-P" : "-p"; From 0720c64e569b173dc8d399fe868614be036c05f1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:50:01 +0200 Subject: [PATCH 0436/3720] Fixup whitespace in compat/regex.[ch] Signed-off-by: Johannes Sixt --- compat/regex.c | 3832 ++++++++++++++++++++++++------------------------ compat/regex.h | 102 +- 2 files changed, 1967 insertions(+), 1967 deletions(-) diff --git a/compat/regex.c b/compat/regex.c index 1d39e08d47..87b33e4669 100644 --- a/compat/regex.c +++ b/compat/regex.c @@ -49,7 +49,7 @@ /* This must be nonzero for the wordchar and notwordchar pattern commands in re_match_2. */ -#ifndef Sword +#ifndef Sword #define Sword 1 #endif @@ -146,8 +146,8 @@ init_syntax_once () use `alloca' instead of `malloc'. This is because using malloc in re_search* or re_match* could cause memory leaks when C-g is used in Emacs; also, malloc is slower and causes storage fragmentation. On - the other hand, malloc is more portable, and easier to debug. - + the other hand, malloc is more portable, and easier to debug. + Because we sometimes use alloca, some routines have to be macros, not functions -- `alloca'-allocated space disappears at the end of the function it is called in. */ @@ -172,7 +172,7 @@ init_syntax_once () #ifndef _AIX /* Already did AIX, up at the top. */ char *alloca (); #endif /* not _AIX */ -#endif /* not HAVE_ALLOCA_H */ +#endif /* not HAVE_ALLOCA_H */ #endif /* not __GNUC__ */ #endif /* not alloca */ @@ -223,108 +223,108 @@ typedef enum { no_op = 0, - /* Followed by one byte giving n, then by n literal bytes. */ + /* Followed by one byte giving n, then by n literal bytes. */ exactn = 1, - /* Matches any (more or less) character. */ + /* Matches any (more or less) character. */ anychar, - /* Matches any one char belonging to specified set. First - following byte is number of bitmap bytes. Then come bytes - for a bitmap saying which chars are in. Bits in each byte - are ordered low-bit-first. A character is in the set if its - bit is 1. A character too large to have a bit in the map is - automatically not in the set. */ + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ charset, - /* Same parameters as charset, but match any character that is - not one of those specified. */ + /* Same parameters as charset, but match any character that is + not one of those specified. */ charset_not, - /* Start remembering the text that is matched, for storing in a - register. Followed by one byte with the register number, in - the range 0 to one less than the pattern buffer's re_nsub - field. Then followed by one byte with the number of groups - inner to this one. (This last has to be part of the - start_memory only because we need it in the on_failure_jump - of re_match_2.) */ + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ start_memory, - /* Stop remembering the text that is matched and store it in a - memory register. Followed by one byte with the register - number, in the range 0 to one less than `re_nsub' in the - pattern buffer, and one byte with the number of inner groups, - just like `start_memory'. (We need the number of inner - groups here because we don't have any easy way of finding the - corresponding start_memory when we're at a stop_memory.) */ + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ stop_memory, - /* Match a duplicate of something remembered. Followed by one - byte containing the register number. */ + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ duplicate, - /* Fail unless at beginning of line. */ + /* Fail unless at beginning of line. */ begline, - /* Fail unless at end of line. */ + /* Fail unless at end of line. */ endline, - /* Succeeds if at beginning of buffer (if emacs) or at beginning - of string to be matched (if not). */ + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ begbuf, - /* Analogously, for end of buffer/string. */ + /* Analogously, for end of buffer/string. */ endbuf, - - /* Followed by two byte relative address to which to jump. */ - jump, + + /* Followed by two byte relative address to which to jump. */ + jump, /* Same as jump, but marks the end of an alternative. */ jump_past_alt, - /* Followed by two-byte relative address of place to resume at - in case of failure. */ + /* Followed by two-byte relative address of place to resume at + in case of failure. */ on_failure_jump, - - /* Like on_failure_jump, but pushes a placeholder instead of the - current string position when executed. */ + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ on_failure_keep_string_jump, - - /* Throw away latest failure point and then jump to following - two-byte relative address. */ + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ pop_failure_jump, - /* Change to pop_failure_jump if know won't have to backtrack to - match; otherwise change to jump. This is used to jump - back to the beginning of a repeat. If what follows this jump - clearly won't match what the repeat does, such that we can be - sure that there is no use backtracking out of repetitions - already matched, then we change it to a pop_failure_jump. - Followed by two-byte address. */ + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ maybe_pop_jump, - /* Jump to following two-byte address, and push a dummy failure - point. This failure point will be thrown away if an attempt - is made to use it for a failure. A `+' construct makes this - before the first repeat. Also used as an intermediary kind - of jump when compiling an alternative. */ + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ dummy_failure_jump, /* Push a dummy failure point and continue. Used at the end of alternatives. */ push_dummy_failure, - /* Followed by two-byte relative address and two-byte number n. - After matching N times, jump to the address upon failure. */ + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ succeed_n, - /* Followed by two-byte relative address, and two-byte number n. - Jump to the address N times, then fail. */ + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ jump_n, - /* Set the following two-byte relative address to the - subsequent two-byte number. The address *includes* the two - bytes of number. */ + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ set_number_at, wordchar, /* Matches any word-constituent character. */ @@ -342,7 +342,7 @@ typedef enum after_dot, /* Succeeds if after point. */ /* Matches any character whose syntax is specified. Followed by - a byte which contains a syntax code, e.g., Sword. */ + a byte which contains a syntax code, e.g., Sword. */ syntaxspec, /* Matches any character whose syntax is not that specified. */ @@ -385,7 +385,7 @@ extract_number (dest, source) int *dest; unsigned char *source; { - int temp = SIGN_EXTEND_CHAR (*(source + 1)); + int temp = SIGN_EXTEND_CHAR (*(source + 1)); *dest = *source & 0377; *dest += temp << 8; } @@ -411,7 +411,7 @@ static void extract_number_and_incr (destination, source) int *destination; unsigned char **source; -{ +{ extract_number (destination, *source); *source += 2; } @@ -460,27 +460,27 @@ print_fastmap (fastmap) char *fastmap; { unsigned was_a_range = 0; - unsigned i = 0; - + unsigned i = 0; + while (i < (1 << BYTEWIDTH)) { if (fastmap[i++]) { was_a_range = 0; - printchar (i - 1); - while (i < (1 << BYTEWIDTH) && fastmap[i]) - { - was_a_range = 1; - i++; - } + printchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } if (was_a_range) - { - printf ("-"); - printchar (i - 1); - } - } + { + printf ("-"); + printchar (i - 1); + } + } } - putchar ('\n'); + putchar ('\n'); } @@ -501,36 +501,36 @@ print_partial_compiled_pattern (start, end) printf ("(null)\n"); return; } - + /* Loop over pattern commands. */ while (p < pend) { switch ((re_opcode_t) *p++) { - case no_op: - printf ("/no_op"); - break; + case no_op: + printf ("/no_op"); + break; case exactn: mcnt = *p++; - printf ("/exactn/%d", mcnt); - do + printf ("/exactn/%d", mcnt); + do { - putchar ('/'); + putchar ('/'); printchar (*p++); - } - while (--mcnt); - break; + } + while (--mcnt); + break; case start_memory: - mcnt = *p++; - printf ("/start_memory/%d/%d", mcnt, *p++); - break; + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; case stop_memory: - mcnt = *p++; + mcnt = *p++; printf ("/stop_memory/%d/%d", mcnt, *p++); - break; + break; case duplicate: printf ("/duplicate/%d", *p++); @@ -541,131 +541,131 @@ print_partial_compiled_pattern (start, end) break; case charset: - case charset_not: - { - register int c; + case charset_not: + { + register int c; - printf ("/charset%s", - (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); - - assert (p + *p < pend); + printf ("/charset%s", + (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); - for (c = 0; c < *p; c++) - { - unsigned bit; - unsigned char map_byte = p[1 + c]; - - putchar ('/'); + assert (p + *p < pend); + + for (c = 0; c < *p; c++) + { + unsigned bit; + unsigned char map_byte = p[1 + c]; + + putchar ('/'); for (bit = 0; bit < BYTEWIDTH; bit++) - if (map_byte & (1 << bit)) - printchar (c * BYTEWIDTH + bit); - } + if (map_byte & (1 << bit)) + printchar (c * BYTEWIDTH + bit); + } p += 1 + *p; break; } case begline: printf ("/begline"); - break; + break; case endline: - printf ("/endline"); - break; + printf ("/endline"); + break; case on_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/on_failure_jump/0/%d", mcnt); - break; + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_jump/0/%d", mcnt); + break; case on_failure_keep_string_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/on_failure_keep_string_jump/0/%d", mcnt); - break; + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_keep_string_jump/0/%d", mcnt); + break; case dummy_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/dummy_failure_jump/0/%d", mcnt); - break; + extract_number_and_incr (&mcnt, &p); + printf ("/dummy_failure_jump/0/%d", mcnt); + break; case push_dummy_failure: - printf ("/push_dummy_failure"); - break; - - case maybe_pop_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/maybe_pop_jump/0/%d", mcnt); + printf ("/push_dummy_failure"); break; - case pop_failure_jump: + case maybe_pop_jump: extract_number_and_incr (&mcnt, &p); - printf ("/pop_failure_jump/0/%d", mcnt); - break; - - case jump_past_alt: - extract_number_and_incr (&mcnt, &p); - printf ("/jump_past_alt/0/%d", mcnt); - break; - - case jump: - extract_number_and_incr (&mcnt, &p); - printf ("/jump/0/%d", mcnt); + printf ("/maybe_pop_jump/0/%d", mcnt); break; - case succeed_n: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); - break; - - case jump_n: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); - break; - - case set_number_at: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); - break; - - case wordbound: + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/pop_failure_jump/0/%d", mcnt); + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); + printf ("/jump_past_alt/0/%d", mcnt); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + printf ("/jump/0/%d", mcnt); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); + break; + + case wordbound: printf ("/wordbound"); break; case notwordbound: printf ("/notwordbound"); - break; + break; case wordbeg: printf ("/wordbeg"); break; - + case wordend: printf ("/wordend"); - + #ifdef emacs case before_dot: printf ("/before_dot"); - break; + break; case at_dot: printf ("/at_dot"); - break; + break; case after_dot: printf ("/after_dot"); - break; + break; case syntaxspec: - printf ("/syntaxspec"); + printf ("/syntaxspec"); mcnt = *p++; printf ("/%d", mcnt); - break; - + break; + case notsyntaxspec: - printf ("/notsyntaxspec"); + printf ("/notsyntaxspec"); mcnt = *p++; printf ("/%d", mcnt); break; @@ -673,22 +673,22 @@ print_partial_compiled_pattern (start, end) case wordchar: printf ("/wordchar"); - break; - + break; + case notwordchar: printf ("/notwordchar"); - break; + break; case begbuf: printf ("/begbuf"); - break; + break; case endbuf: printf ("/endbuf"); - break; + break; - default: - printf ("?%d", *(p-1)); + default: + printf ("?%d", *(p-1)); } } printf ("/\n"); @@ -731,21 +731,21 @@ print_double_string (where, string1, size1, string2, size2) int size2; { unsigned this_char; - + if (where == NULL) printf ("(null)"); else { if (FIRST_STRING_P (where)) - { - for (this_char = where - string1; this_char < size1; this_char++) - printchar (string1[this_char]); + { + for (this_char = where - string1; this_char < size1; this_char++) + printchar (string1[this_char]); - where = string2; - } + where = string2; + } for (this_char = where - string2; this_char < size2; this_char++) - printchar (string2[this_char]); + printchar (string2[this_char]); } } @@ -782,7 +782,7 @@ re_set_syntax (syntax) reg_syntax_t syntax; { reg_syntax_t ret = re_syntax_options; - + re_syntax_options = syntax; return ret; } @@ -818,7 +818,7 @@ static boolean at_begline_loc_p (), at_endline_loc_p (); static boolean group_in_compile_stack (); static reg_errcode_t compile_range (); -/* Fetch the next character in the uncompiled pattern---translating it +/* Fetch the next character in the uncompiled pattern---translating it if necessary. Also cast from a signed character in the constant string passed to us by the user to an unsigned char that we can use as an array index (in, e.g., `translate'). */ @@ -925,14 +925,14 @@ static reg_errcode_t compile_range (); /* If the buffer moved, move all the pointers into it. */ \ if (old_buffer != bufp->buffer) \ { \ - b = (b - old_buffer) + bufp->buffer; \ - begalt = (begalt - old_buffer) + bufp->buffer; \ - if (fixup_alt_jump) \ - fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ - if (laststart) \ - laststart = (laststart - old_buffer) + bufp->buffer; \ - if (pending_exact) \ - pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ } \ } while (0) @@ -958,7 +958,7 @@ typedef struct pattern_offset_t begalt_offset; pattern_offset_t fixup_alt_jump; pattern_offset_t inner_group_offset; - pattern_offset_t laststart_offset; + pattern_offset_t laststart_offset; regnum_t regnum; } compile_stack_elt_t; @@ -992,16 +992,16 @@ typedef struct { \ PATFETCH (c); \ while (ISDIGIT (c)) \ - { \ - if (num < 0) \ - num = 0; \ - num = num * 10 + c - '0'; \ - if (p == pend) \ - break; \ - PATFETCH (c); \ - } \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ } \ - } + } #define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ @@ -1027,7 +1027,7 @@ typedef struct `fastmap_accurate' is zero; `re_nsub' is the number of subexpressions in PATTERN; `not_bol' and `not_eol' are zero; - + The `fastmap' and `newline_anchor' fields are neither examined nor set. */ @@ -1042,20 +1042,20 @@ regex_compile (pattern, size, syntax, bufp) `char *' (i.e., signed), we declare these variables as unsigned, so they can be reliably used as array indices. */ register unsigned char c, c1; - + /* A random tempory spot in PATTERN. */ const char *p1; /* Points to the end of the buffer, where we should append. */ register unsigned char *b; - + /* Keeps track of unclosed groups. */ compile_stack_type compile_stack; /* Points to the current (ending) position in the pattern. */ const char *p = pattern; const char *pend = pattern + size; - + /* How to translate the characters in the pattern. */ char *translate = bufp->translate; @@ -1076,7 +1076,7 @@ regex_compile (pattern, size, syntax, bufp) /* Place in the uncompiled pattern (i.e., the {) to which to go back if the interval is invalid. */ const char *beg_interval; - + /* Address of the place where a forward jump should go to the end of the containing expression. Each alternative of an `or' -- except the last -- ends with a forward jump of this sort. */ @@ -1092,9 +1092,9 @@ regex_compile (pattern, size, syntax, bufp) if (debug) { unsigned debug_count; - + for (debug_count = 0; debug_count < size; debug_count++) - printchar (pattern[debug_count]); + printchar (pattern[debug_count]); putchar ('\n'); } #endif /* DEBUG */ @@ -1116,9 +1116,9 @@ regex_compile (pattern, size, syntax, bufp) printer (for debugging) will think there's no pattern. We reset it at the end. */ bufp->used = 0; - + /* Always count groups, whether or not bufp->no_sub is set. */ - bufp->re_nsub = 0; + bufp->re_nsub = 0; #if !defined (emacs) && !defined (SYNTAX_TABLE) /* Initialize the syntax table. */ @@ -1129,14 +1129,14 @@ regex_compile (pattern, size, syntax, bufp) { if (bufp->buffer) { /* If zero allocated, but buffer is non-null, try to realloc - enough space. This loses if buffer's address is bogus, but - that is the user's responsibility. */ - RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); - } + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } else - { /* Caller did not allocate a buffer. Do it for them. */ - bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); - } + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } if (!bufp->buffer) return REG_ESPACE; bufp->allocated = INIT_BUF_SIZE; @@ -1150,870 +1150,870 @@ regex_compile (pattern, size, syntax, bufp) PATFETCH (c); switch (c) - { - case '^': - { - if ( /* If at start of pattern, it's an operator. */ - p == pattern + 1 - /* If context independent, it's an operator. */ - || syntax & RE_CONTEXT_INDEP_ANCHORS - /* Otherwise, depends on what's come before. */ - || at_begline_loc_p (pattern, p, syntax)) - BUF_PUSH (begline); - else - goto normal_char; - } - break; + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; - case '$': - { - if ( /* If at end of pattern, it's an operator. */ - p == pend - /* If context independent, it's an operator. */ - || syntax & RE_CONTEXT_INDEP_ANCHORS - /* Otherwise, depends on what's next. */ - || at_endline_loc_p (p, pend, syntax)) - BUF_PUSH (endline); - else - goto normal_char; - } - break; + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; case '+': - case '?': - if ((syntax & RE_BK_PLUS_QM) - || (syntax & RE_LIMITED_OPS)) - goto normal_char; - handle_plus: - case '*': - /* If there is no previous pattern... */ - if (!laststart) - { - if (syntax & RE_CONTEXT_INVALID_OPS) - return REG_BADRPT; - else if (!(syntax & RE_CONTEXT_INDEP_OPS)) - goto normal_char; - } + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } - { - /* Are we optimizing this jump? */ - boolean keep_string_p = false; - - /* 1 means zero (many) matches is allowed. */ - char zero_times_ok = 0, many_times_ok = 0; + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; - /* If there is a sequence of repetition chars, collapse it - down to just one (the right one). We can't combine - interval operators with these because of, e.g., `a{2}*', - which should only match an even number of `a's. */ + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; - for (;;) - { - zero_times_ok |= c != '+'; - many_times_ok |= c != '?'; + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ - if (p == pend) - break; + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; - PATFETCH (c); + if (p == pend) + break; - if (c == '*' - || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) - ; + PATFETCH (c); - else if (syntax & RE_BK_PLUS_QM && c == '\\') - { - if (p == pend) return REG_EESCAPE; + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; - PATFETCH (c1); - if (!(c1 == '+' || c1 == '?')) - { - PATUNFETCH; - PATUNFETCH; - break; - } + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) return REG_EESCAPE; - c = c1; - } - else - { - PATUNFETCH; - break; - } + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } - /* If we get here, we found another repeat character. */ - } + c = c1; + } + else + { + PATUNFETCH; + break; + } - /* Star, etc. applied to an empty pattern is equivalent - to an empty pattern. */ - if (!laststart) - break; + /* If we get here, we found another repeat character. */ + } - /* Now we know whether or not zero matches is allowed - and also whether or not two or more matches is allowed. */ - if (many_times_ok) - { /* More than one repetition is allowed, so put in at the - end a backward relative jump from `b' to before the next - jump we're going to put in below (which jumps from - laststart to after this jump). + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; - But if we are at the `*' in the exact sequence `.*\n', - insert an unconditional jump backwards to the ., - instead of the beginning of the loop. This way we only - push a failure point once, instead of every time - through the loop. */ - assert (p - 1 > pattern); + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). - /* Allocate the space for the jump. */ - GET_BUFFER_SPACE (3); + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); - /* We know we are not at the first character of the pattern, - because laststart was nonzero. And we've already - incremented `p', by the way, to be the character after - the `*'. Do we have to do something analogous here - for null bytes, because of RE_DOT_NOT_NULL? */ - if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') && zero_times_ok - && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') - && !(syntax & RE_DOT_NEWLINE)) - { /* We have .*\n. */ - STORE_JUMP (jump, b, laststart); - keep_string_p = true; - } - else - /* Anything else. */ - STORE_JUMP (maybe_pop_jump, b, laststart - 3); + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); - /* We've added more stuff to the buffer. */ - b += 3; - } + /* We've added more stuff to the buffer. */ + b += 3; + } - /* On failure, jump from laststart to b + 3, which will be the - end of the buffer after this jump is inserted. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump - : on_failure_jump, - laststart, b + 3); - pending_exact = 0; - b += 3; + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; - if (!zero_times_ok) - { - /* At least one repetition is required, so insert a - `dummy_failure_jump' before the initial - `on_failure_jump' instruction of the loop. This - effects a skip over that instruction the first time - we hit that loop. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); - b += 3; - } - } + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } break; case '.': - laststart = b; - BUF_PUSH (anychar); - break; + laststart = b; + BUF_PUSH (anychar); + break; - case '[': - { - boolean had_char_class = false; + case '[': + { + boolean had_char_class = false; - if (p == pend) return REG_EBRACK; + if (p == pend) return REG_EBRACK; - /* Ensure that we have enough space to push a charset: the - opcode, the length count, and the bitset; 34 bytes in all. */ + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ GET_BUFFER_SPACE (34); - laststart = b; + laststart = b; - /* We test `*p == '^' twice, instead of using an if - statement, so we only need one BUF_PUSH. */ - BUF_PUSH (*p == '^' ? charset_not : charset); - if (*p == '^') - p++; + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; - /* Remember the first position in the bracket expression. */ - p1 = p; + /* Remember the first position in the bracket expression. */ + p1 = p; - /* Push the number of bytes in the bitmap. */ - BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); - /* Clear the whole map. */ - bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); - /* charset_not matches newline according to a syntax bit. */ - if ((re_opcode_t) b[-2] == charset_not - && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) - SET_LIST_BIT ('\n'); + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); - /* Read in characters and ranges, setting map bits. */ - for (;;) - { - if (p == pend) return REG_EBRACK; + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) return REG_EBRACK; - PATFETCH (c); + PATFETCH (c); - /* \ might escape characters inside [...] and [^...]. */ - if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') - { - if (p == pend) return REG_EESCAPE; + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) return REG_EESCAPE; - PATFETCH (c1); - SET_LIST_BIT (c1); - continue; - } + PATFETCH (c1); + SET_LIST_BIT (c1); + continue; + } - /* Could be the end of the bracket expression. If it's - not (i.e., when the bracket expression is `[]' so - far), the ']' character bit gets set way below. */ - if (c == ']' && p != p1 + 1) - break; + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; - /* Look ahead to see if it's a range when the last thing - was a character class. */ - if (had_char_class && c == '-' && *p != ']') - return REG_ERANGE; + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + return REG_ERANGE; - /* Look ahead to see if it's a range when the last thing - was a character: if this is a hyphen not at the - beginning or the end of a list, then it's the range - operator. */ - if (c == '-' - && !(p - 2 >= pattern && p[-2] == '[') - && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') - && *p != ']') - { - reg_errcode_t ret - = compile_range (&p, pend, translate, syntax, b); - if (ret != REG_NOERROR) return ret; - } + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } - else if (p[0] == '-' && p[1] != ']') - { /* This handles ranges made up of characters only. */ - reg_errcode_t ret; + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; /* Move past the `-'. */ - PATFETCH (c1); - - ret = compile_range (&p, pend, translate, syntax, b); - if (ret != REG_NOERROR) return ret; - } + PATFETCH (c1); - /* See if we're at the beginning of a possible character - class. */ + ret = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } - else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') - { /* Leave room for the null. */ - char str[CHAR_CLASS_MAX_LENGTH + 1]; + /* See if we're at the beginning of a possible character + class. */ - PATFETCH (c); - c1 = 0; + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; - /* If pattern is `[[:'. */ - if (p == pend) return REG_EBRACK; + PATFETCH (c); + c1 = 0; - for (;;) - { - PATFETCH (c); - if (c == ':' || c == ']' || p == pend - || c1 == CHAR_CLASS_MAX_LENGTH) - break; - str[c1++] = c; - } - str[c1] = '\0'; + /* If pattern is `[[:'. */ + if (p == pend) return REG_EBRACK; - /* If isn't a word bracketed by `[:' and:`]': - undo the ending character, the letters, and leave - the leading `:' and `[' (but set bits for them). */ - if (c == ':' && *p == ']') - { - int ch; - boolean is_alnum = STREQ (str, "alnum"); - boolean is_alpha = STREQ (str, "alpha"); - boolean is_blank = STREQ (str, "blank"); - boolean is_cntrl = STREQ (str, "cntrl"); - boolean is_digit = STREQ (str, "digit"); - boolean is_graph = STREQ (str, "graph"); - boolean is_lower = STREQ (str, "lower"); - boolean is_print = STREQ (str, "print"); - boolean is_punct = STREQ (str, "punct"); - boolean is_space = STREQ (str, "space"); - boolean is_upper = STREQ (str, "upper"); - boolean is_xdigit = STREQ (str, "xdigit"); - - if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; + for (;;) + { + PATFETCH (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; - /* Throw away the ] at the end of the character - class. */ - PATFETCH (c); + /* If isn't a word bracketed by `[:' and:`]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); - if (p == pend) return REG_EBRACK; + if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; - for (ch = 0; ch < 1 << BYTEWIDTH; ch++) - { - if ( (is_alnum && ISALNUM (ch)) - || (is_alpha && ISALPHA (ch)) - || (is_blank && ISBLANK (ch)) - || (is_cntrl && ISCNTRL (ch)) - || (is_digit && ISDIGIT (ch)) - || (is_graph && ISGRAPH (ch)) - || (is_lower && ISLOWER (ch)) - || (is_print && ISPRINT (ch)) - || (is_punct && ISPUNCT (ch)) - || (is_space && ISSPACE (ch)) - || (is_upper && ISUPPER (ch)) - || (is_xdigit && ISXDIGIT (ch))) - SET_LIST_BIT (ch); - } - had_char_class = true; - } - else - { - c1++; - while (c1--) - PATUNFETCH; - SET_LIST_BIT ('['); - SET_LIST_BIT (':'); - had_char_class = false; - } - } - else - { - had_char_class = false; - SET_LIST_BIT (c); - } - } + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); - /* Discard any (non)matching list bytes that are all 0 at the - end of the map. Decrease the map-length byte too. */ - while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) - b[-1]--; - b += b[-1]; - } - break; + if (p == pend) return REG_EBRACK; + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch)) + || (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch)) + || (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; case '(': - if (syntax & RE_NO_BK_PARENS) - goto handle_open; - else - goto normal_char; + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; - case ')': - if (syntax & RE_NO_BK_PARENS) - goto handle_close; - else - goto normal_char; + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; - case '\n': - if (syntax & RE_NEWLINE_ALT) - goto handle_alt; - else - goto normal_char; + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; case '|': - if (syntax & RE_NO_BK_VBAR) - goto handle_alt; - else - goto normal_char; + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; - case '{': - if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) - goto handle_interval; - else - goto normal_char; + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; - case '\\': - if (p == pend) return REG_EESCAPE; + case '\\': + if (p == pend) return REG_EESCAPE; - /* Do not translate the character after the \, so that we can - distinguish, e.g., \B from \b, even if we normally would - translate, e.g., B to b. */ - PATFETCH_RAW (c); + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); - switch (c) - { - case '(': - if (syntax & RE_NO_BK_PARENS) - goto normal_backslash; + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; - handle_open: - bufp->re_nsub++; - regnum++; + handle_open: + bufp->re_nsub++; + regnum++; - if (COMPILE_STACK_FULL) - { - RETALLOC (compile_stack.stack, compile_stack.size << 1, - compile_stack_elt_t); - if (compile_stack.stack == NULL) return REG_ESPACE; + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; - compile_stack.size <<= 1; - } + compile_stack.size <<= 1; + } - /* These are the values to restore when we hit end of this - group. They are all relative offsets, so that if the - whole pattern moves because of realloc, they will still - be valid. */ - COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; - COMPILE_STACK_TOP.fixup_alt_jump - = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; - COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; - COMPILE_STACK_TOP.regnum = regnum; + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; - /* We will eventually replace the 0 with the number of - groups inner to this one. But do not push a - start_memory for groups beyond the last one we can - represent in the compiled pattern. */ - if (regnum <= MAX_REGNUM) - { - COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; - BUF_PUSH_3 (start_memory, regnum, 0); - } - - compile_stack.avail++; + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } - fixup_alt_jump = 0; - laststart = 0; - begalt = b; + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; /* If we've reached MAX_REGNUM groups, then this open won't actually generate any code, so we'll have to clear pending_exact explicitly. */ pending_exact = 0; - break; + break; - case ')': - if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; - if (COMPILE_STACK_EMPTY) - { - if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) - goto normal_backslash; - else - return REG_ERPAREN; - } + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + return REG_ERPAREN; + } - handle_close: - if (fixup_alt_jump) - { /* Push a dummy failure point at the end of the - alternative for a possible future - `pop_failure_jump' to pop. See comments at - `push_dummy_failure' in `re_match_2'. */ - BUF_PUSH (push_dummy_failure); - - /* We allocated space for this jump when we assigned - to `fixup_alt_jump', in the `handle_alt' case below. */ - STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); - } + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); - /* See similar code for backslashed left paren above. */ - if (COMPILE_STACK_EMPTY) - { - if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) - goto normal_char; - else - return REG_ERPAREN; - } + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } - /* Since we just checked for an empty stack above, this - ``can't happen''. */ - assert (compile_stack.avail != 0); - { - /* We don't just want to restore into `regnum', because - later groups should continue to be numbered higher, - as in `(ab)c(de)' -- the second group is #2. */ - regnum_t this_group_regnum; + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + return REG_ERPAREN; + } - compile_stack.avail--; - begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; - fixup_alt_jump - = COMPILE_STACK_TOP.fixup_alt_jump - ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 - : 0; - laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; - this_group_regnum = COMPILE_STACK_TOP.regnum; + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; /* If we've reached MAX_REGNUM groups, then this open won't actually generate any code, so we'll have to clear pending_exact explicitly. */ pending_exact = 0; - /* We're at the end of the group, so now we know how many - groups were inside this one. */ - if (this_group_regnum <= MAX_REGNUM) - { - unsigned char *inner_group_loc - = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; - - *inner_group_loc = regnum - this_group_regnum; - BUF_PUSH_3 (stop_memory, this_group_regnum, - regnum - this_group_regnum); - } - } - break; + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; - case '|': /* `\|'. */ - if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) - goto normal_backslash; - handle_alt: - if (syntax & RE_LIMITED_OPS) - goto normal_char; + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; - /* Insert before the previous alternative a jump which - jumps to this alternative if the former fails. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (on_failure_jump, begalt, b + 6); - pending_exact = 0; - b += 3; + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; - /* The alternative before this one has a jump after it - which gets executed if it gets matched. Adjust that - jump so it will jump to this alternative's analogous - jump (put in below, which in turn will jump to the next - (if any) alternative's such jump, etc.). The last such - jump jumps to the correct final destination. A picture: - _____ _____ - | | | | - | v | v - a | b | c + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c - If we are at `b', then fixup_alt_jump right now points to a - three-byte space after `a'. We'll put in the jump, set - fixup_alt_jump to right after `b', and leave behind three - bytes which we'll fill in when we get to after `c'. */ + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ - if (fixup_alt_jump) - STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); - /* Mark and leave space for a jump after this alternative, - to be filled in later either by next alternative or - when know we're at the end of a series of alternatives. */ - fixup_alt_jump = b; - GET_BUFFER_SPACE (3); - b += 3; + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; - laststart = 0; - begalt = b; - break; + laststart = 0; + begalt = b; + break; - case '{': - /* If \{ is a literal. */ - if (!(syntax & RE_INTERVALS) - /* If we're at `\{' and it's not the open-interval - operator. */ - || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) - || (p - 2 == pattern && p == pend)) - goto normal_backslash; + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + || (p - 2 == pattern && p == pend)) + goto normal_backslash; - handle_interval: - { - /* If got here, then the syntax allows intervals. */ + handle_interval: + { + /* If got here, then the syntax allows intervals. */ - /* At least (most) this many matches must be made. */ - int lower_bound = -1, upper_bound = -1; + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; - beg_interval = p - 1; + beg_interval = p - 1; - if (p == pend) - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_EBRACE; - } + if (p == pend) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_EBRACE; + } - GET_UNSIGNED_NUMBER (lower_bound); + GET_UNSIGNED_NUMBER (lower_bound); - if (c == ',') - { - GET_UNSIGNED_NUMBER (upper_bound); - if (upper_bound < 0) upper_bound = RE_DUP_MAX; - } - else - /* Interval such as `{1}' => match exactly once. */ - upper_bound = lower_bound; + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; - if (lower_bound < 0 || upper_bound > RE_DUP_MAX - || lower_bound > upper_bound) - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_BADBR; - } + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } - if (!(syntax & RE_NO_BK_BRACES)) - { - if (c != '\\') return REG_EBRACE; + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') return REG_EBRACE; - PATFETCH (c); - } + PATFETCH (c); + } - if (c != '}') - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_BADBR; - } + if (c != '}') + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } - /* We just parsed a valid interval. */ + /* We just parsed a valid interval. */ - /* If it's invalid to have no preceding re. */ - if (!laststart) - { - if (syntax & RE_CONTEXT_INVALID_OPS) - return REG_BADRPT; - else if (syntax & RE_CONTEXT_INDEP_OPS) - laststart = b; - else - goto unfetch_interval; - } + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } - /* If the upper bound is zero, don't want to succeed at - all; jump from `laststart' to `b + 3', which will be - the end of the buffer after we insert the jump. */ - if (upper_bound == 0) - { - GET_BUFFER_SPACE (3); - INSERT_JUMP (jump, laststart, b + 3); - b += 3; - } + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } - /* Otherwise, we have a nontrivial interval. When - we're all done, the pattern will look like: - set_number_at - set_number_at - succeed_n - - jump_n - (The upper bound and `jump_n' are omitted if - `upper_bound' is 1, though.) */ - else - { /* If the upper bound is > 1, we need to insert - more at the end of the loop. */ - unsigned nbytes = 10 + (upper_bound > 1) * 10; + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; - GET_BUFFER_SPACE (nbytes); + GET_BUFFER_SPACE (nbytes); - /* Initialize lower bound of the `succeed_n', even - though it will be set during matching by its - attendant `set_number_at' (inserted next), - because `re_compile_fastmap' needs to know. - Jump to the `jump_n' we might insert below. */ - INSERT_JUMP2 (succeed_n, laststart, - b + 5 + (upper_bound > 1) * 5, - lower_bound); - b += 5; + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; - /* Code to initialize the lower bound. Insert - before the `succeed_n'. The `5' is the last two - bytes of this `set_number_at', plus 3 bytes of - the following `succeed_n'. */ - insert_op2 (set_number_at, laststart, 5, lower_bound, b); - b += 5; + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; - if (upper_bound > 1) - { /* More than one repetition is allowed, so - append a backward jump to the `succeed_n' - that starts this interval. - - When we've reached this during matching, - we'll have matched the interval once, so - jump back only `upper_bound - 1' times. */ - STORE_JUMP2 (jump_n, b, laststart + 5, - upper_bound - 1); - b += 5; + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. - /* The location we want to set is the second - parameter of the `jump_n'; that is `b-2' as - an absolute address. `laststart' will be - the `set_number_at' we're about to insert; - `laststart+3' the number to set, the source - for the relative address. But we are - inserting into the middle of the pattern -- - so everything is getting moved up by 5. - Conclusion: (b - 2) - (laststart + 3) + 5, - i.e., b - laststart. - - We insert this at the beginning of the loop - so that if we fail during matching, we'll - reinitialize the bounds. */ - insert_op2 (set_number_at, laststart, b - laststart, - upper_bound - 1, b); - b += 5; - } - } - pending_exact = 0; - beg_interval = NULL; - } - break; + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; - unfetch_interval: - /* If an invalid interval, match the characters as literals. */ - assert (beg_interval); - p = beg_interval; - beg_interval = NULL; + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. - /* normal_char and normal_backslash need `c'. */ - PATFETCH (c); + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; - if (!(syntax & RE_NO_BK_BRACES)) - { - if (p > pattern && p[-1] == '\\') - goto normal_backslash; - } - goto normal_char; + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; #ifdef emacs - /* There is no way to specify the before_dot and after_dot - operators. rms says this is ok. --karl */ - case '=': - BUF_PUSH (at_dot); - break; + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; - case 's': - laststart = b; - PATFETCH (c); - BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); - break; + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; - case 'S': - laststart = b; - PATFETCH (c); - BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); - break; + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; #endif /* emacs */ - case 'w': - laststart = b; - BUF_PUSH (wordchar); - break; + case 'w': + laststart = b; + BUF_PUSH (wordchar); + break; - case 'W': - laststart = b; - BUF_PUSH (notwordchar); - break; + case 'W': + laststart = b; + BUF_PUSH (notwordchar); + break; - case '<': - BUF_PUSH (wordbeg); - break; + case '<': + BUF_PUSH (wordbeg); + break; - case '>': - BUF_PUSH (wordend); - break; + case '>': + BUF_PUSH (wordend); + break; - case 'b': - BUF_PUSH (wordbound); - break; + case 'b': + BUF_PUSH (wordbound); + break; - case 'B': - BUF_PUSH (notwordbound); - break; + case 'B': + BUF_PUSH (notwordbound); + break; - case '`': - BUF_PUSH (begbuf); - break; + case '`': + BUF_PUSH (begbuf); + break; - case '\'': - BUF_PUSH (endbuf); - break; + case '\'': + BUF_PUSH (endbuf); + break; - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - if (syntax & RE_NO_BK_REFS) - goto normal_char; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; - c1 = c - '0'; + c1 = c - '0'; - if (c1 > regnum) - return REG_ESUBREG; + if (c1 > regnum) + return REG_ESUBREG; - /* Can't back reference to a subexpression if inside of it. */ - if (group_in_compile_stack (compile_stack, c1)) - goto normal_char; + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, c1)) + goto normal_char; - laststart = b; - BUF_PUSH_2 (duplicate, c1); - break; + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; - case '+': - case '?': - if (syntax & RE_BK_PLUS_QM) - goto handle_plus; - else - goto normal_backslash; + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; - default: - normal_backslash: - /* You might think it would be useful for \ to mean - not to translate; but if we don't translate it - it will never match anything. */ - c = TRANSLATE (c); - goto normal_char; - } - break; + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; default: - /* Expects the character in `c'. */ + /* Expects the character in `c'. */ normal_char: /* If no exactn currently being built. */ - if (!pending_exact + if (!pending_exact - /* If last exactn not at current position. */ - || pending_exact + *pending_exact + 1 != b - - /* We have only one byte following the exactn for the count. */ + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ || *pending_exact == (1 << BYTEWIDTH) - 1 - /* If followed by a repetition operator. */ - || *p == '*' || *p == '^' + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' || ((syntax & RE_BK_PLUS_QM) ? *p == '\\' && (p[1] == '+' || p[1] == '?') : (*p == '+' || *p == '?')) || ((syntax & RE_INTERVALS) - && ((syntax & RE_NO_BK_BRACES) + && ((syntax & RE_NO_BK_BRACES) ? *p == '{' - : (p[0] == '\\' && p[1] == '{')))) + : (p[0] == '\\' && p[1] == '{')))) { /* Start building a new exactn. */ - - laststart = b; + + laststart = b; BUF_PUSH_2 (exactn, 0); pending_exact = b - 1; - } - + } + BUF_PUSH (c); - (*pending_exact)++; + (*pending_exact)++; break; - } /* switch (c) */ + } /* switch (c) */ } /* while p != pend */ - + /* Through the pattern now. */ - + if (fixup_alt_jump) STORE_JUMP (jump_past_alt, fixup_alt_jump, b); - if (!COMPILE_STACK_EMPTY) + if (!COMPILE_STACK_EMPTY) return REG_EPAREN; free (compile_stack.stack); @@ -2069,14 +2069,14 @@ insert_op1 (op, loc, arg, end) re_opcode_t op; unsigned char *loc; int arg; - unsigned char *end; + unsigned char *end; { register unsigned char *pfrom = end; register unsigned char *pto = end + 3; while (pfrom != loc) *--pto = *--pfrom; - + store_op1 (op, loc, arg); } @@ -2088,14 +2088,14 @@ insert_op2 (op, loc, arg1, arg2, end) re_opcode_t op; unsigned char *loc; int arg1, arg2; - unsigned char *end; + unsigned char *end; { register unsigned char *pfrom = end; register unsigned char *pto = end + 5; while (pfrom != loc) *--pto = *--pfrom; - + store_op2 (op, loc, arg1, arg2); } @@ -2111,7 +2111,7 @@ at_begline_loc_p (pattern, p, syntax) { const char *prev = p - 2; boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; - + return /* After a subexpression? */ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) @@ -2131,18 +2131,18 @@ at_endline_loc_p (p, pend, syntax) const char *next = p; boolean next_backslash = *next == '\\'; const char *next_next = p + 1 < pend ? p + 1 : NULL; - + return /* Before a subexpression? */ (syntax & RE_NO_BK_PARENS ? *next == ')' - : next_backslash && next_next && *next_next == ')') + : next_backslash && next_next && *next_next == ')') /* Before an alternative? */ || (syntax & RE_NO_BK_VBAR ? *next == '|' - : next_backslash && next_next && *next_next == '|'); + : next_backslash && next_next && *next_next == '|'); } -/* Returns true if REGNUM is in one of COMPILE_STACK's elements and +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and false if it's not. */ static boolean @@ -2152,8 +2152,8 @@ group_in_compile_stack (compile_stack, regnum) { int this_element; - for (this_element = compile_stack.avail - 1; - this_element >= 0; + for (this_element = compile_stack.avail - 1; + this_element >= 0; this_element--) if (compile_stack.stack[this_element].regnum == regnum) return true; @@ -2167,9 +2167,9 @@ group_in_compile_stack (compile_stack, regnum) starting character is in `P[-2]'. (`P[-1]' is the character `-'.) Then we set the translation of all bits between the starting and ending characters (inclusive) in the compiled pattern B. - + Return an error code. - + We use these short variable names so we can use the same macros as `regex_compile' itself. */ @@ -2184,7 +2184,7 @@ compile_range (p_ptr, pend, translate, syntax, b) const char *p = *p_ptr; int range_start, range_end; - + if (p == pend) return REG_ERANGE; @@ -2193,7 +2193,7 @@ compile_range (p_ptr, pend, translate, syntax, b) is set, the range endpoints will be negative if we fetch using a signed char *. - We also want to fetch the endpoints without translating them; the + We also want to fetch the endpoints without translating them; the appropriate translation is done in the bit-setting loop below. */ range_start = ((unsigned char *) p)[-2]; range_end = ((unsigned char *) p)[0]; @@ -2214,14 +2214,14 @@ compile_range (p_ptr, pend, translate, syntax, b) { SET_LIST_BIT (TRANSLATE (this_char)); } - + return REG_NOERROR; } /* Failure stack declarations and macros; both re_compile_fastmap and re_match_2 use a failure stack. These have to be macros because of REGEX_ALLOCATE. */ - + /* Number of failure points for which to initially allocate space when matching. If this number is exceeded, we allocate more @@ -2269,25 +2269,25 @@ typedef struct /* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. Return 1 if succeeds, and 0 if either ran out of memory - allocating space for it or it was already too large. - + allocating space for it or it was already too large. + REGEX_REALLOCATE requires `destination' be declared. */ #define DOUBLE_FAIL_STACK(fail_stack) \ ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \ ? 0 \ : ((fail_stack).stack = (fail_stack_elt_t *) \ - REGEX_REALLOCATE ((fail_stack).stack, \ - (fail_stack).size * sizeof (fail_stack_elt_t), \ - ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + REGEX_REALLOCATE ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ \ (fail_stack).stack == NULL \ ? 0 \ : ((fail_stack).size <<= 1, \ - 1))) + 1))) -/* Push PATTERN_OP on FAIL_STACK. +/* Push PATTERN_OP on FAIL_STACK. Return 1 if was able to do so and 0 if ran out of memory allocating space to do so. */ @@ -2318,12 +2318,12 @@ typedef struct /* Push the information about the state we will need - if we ever fail back to it. - + if we ever fail back to it. + Requires variables fail_stack, regstart, regend, reg_info, and num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be declared. - + Does `return FAILURE_CODE' if runs out of memory. */ #define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ @@ -2332,7 +2332,7 @@ typedef struct /* Must be int, so when we don't save any registers, the arithmetic \ of 0 + -1 isn't done as unsigned. */ \ int this_reg; \ - \ + \ DEBUG_STATEMENT (failure_id++); \ DEBUG_STATEMENT (nfailure_points_pushed++); \ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ @@ -2345,39 +2345,39 @@ typedef struct /* Ensure we have enough space allocated for what we will push. */ \ while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ { \ - if (!DOUBLE_FAIL_STACK (fail_stack)) \ - return failure_code; \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ \ - DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ (fail_stack).size); \ - DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ } \ \ /* Push the info, starting with the registers. */ \ DEBUG_PRINT1 ("\n"); \ \ for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ - this_reg++) \ + this_reg++) \ { \ DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \ - DEBUG_STATEMENT (num_regs_pushed++); \ + DEBUG_STATEMENT (num_regs_pushed++); \ \ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ - PUSH_FAILURE_ITEM (regstart[this_reg]); \ - \ + PUSH_FAILURE_ITEM (regstart[this_reg]); \ + \ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ - PUSH_FAILURE_ITEM (regend[this_reg]); \ + PUSH_FAILURE_ITEM (regend[this_reg]); \ \ DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \ - DEBUG_PRINT2 (" match_null=%d", \ - REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ - DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ - DEBUG_PRINT2 (" matched_something=%d", \ - MATCHED_SOMETHING (reg_info[this_reg])); \ - DEBUG_PRINT2 (" ever_matched=%d", \ - EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ DEBUG_PRINT1 ("\n"); \ - PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ + PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ } \ \ DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\ @@ -2431,7 +2431,7 @@ typedef struct LOW_REG, HIGH_REG -- the highest and lowest active registers. REGSTART, REGEND -- arrays of string positions. REG_INFO -- array of information about each subexpression. - + Also assumes the variables `fail_stack' and (if debugging), `bufp', `pend', `string1', `size1', `string2', and `size2'. */ @@ -2499,7 +2499,7 @@ typedef struct The caller must supply the address of a (1 << BYTEWIDTH)-byte data area as BUFP->fastmap. - + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in the pattern buffer. @@ -2516,7 +2516,7 @@ re_compile_fastmap (bufp) #endif /* We don't push any register information onto the failure stack. */ unsigned num_regs = 0; - + register char *fastmap = bufp->fastmap; unsigned char *pattern = bufp->buffer; unsigned long size = bufp->used; @@ -2533,27 +2533,27 @@ re_compile_fastmap (bufp) boolean succeed_n_p = false; assert (fastmap != NULL && p != NULL); - + INIT_FAIL_STACK (); bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ bufp->fastmap_accurate = 1; /* It will be when we're done. */ bufp->can_be_null = 0; - + while (p != pend || !FAIL_STACK_EMPTY ()) { if (p == pend) - { - bufp->can_be_null |= path_can_be_null; - - /* Reset for next path. */ - path_can_be_null = true; - - p = fail_stack.stack[--fail_stack.avail]; + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail]; } /* We should never be about to go beyond the end of the pattern. */ assert (p < pend); - + #ifdef SWITCH_ENUM_BUG switch ((int) ((re_opcode_t) *p++)) #else @@ -2561,40 +2561,40 @@ re_compile_fastmap (bufp) #endif { - /* I guess the idea here is to simply not bother with a fastmap - if a backreference is used, since it's too hard to figure out - the fastmap for the corresponding group. Setting - `can_be_null' stops `re_search_2' from using the fastmap, so - that is all we do. */ + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ case duplicate: bufp->can_be_null = 1; - return 0; + return 0; /* Following are the cases which match a character. These end - with `break'. */ + with `break'. */ case exactn: - fastmap[p[1]] = 1; + fastmap[p[1]] = 1; break; - case charset: - for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) - fastmap[j] = 1; + fastmap[j] = 1; break; case charset_not: /* Chars beyond end of map must be allowed. */ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; + fastmap[j] = 1; for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) - fastmap[j] = 1; - break; + fastmap[j] = 1; + break; case wordchar: @@ -2611,26 +2611,26 @@ re_compile_fastmap (bufp) break; - case anychar: - /* `.' matches anything ... */ + case anychar: + /* `.' matches anything ... */ for (j = 0; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; + fastmap[j] = 1; - /* ... except perhaps newline. */ - if (!(bufp->syntax & RE_DOT_NEWLINE)) - fastmap['\n'] = 0; + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = 0; - /* Return if we have already set `can_be_null'; if we have, - then the fastmap is irrelevant. Something's wrong here. */ + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ else if (bufp->can_be_null) return 0; - /* Otherwise, have to check alternative paths. */ + /* Otherwise, have to check alternative paths. */ break; #ifdef emacs - case syntaxspec: + case syntaxspec: k = *p++; for (j = 0; j < (1 << BYTEWIDTH); j++) if (SYNTAX (j) == (enum syntaxcode) k) @@ -2647,126 +2647,126 @@ re_compile_fastmap (bufp) /* All cases after this match the empty string. These end with - `continue'. */ + `continue'. */ case before_dot: case at_dot: case after_dot: - continue; + continue; #endif /* not emacs */ - case no_op: - case begline: - case endline: + case no_op: + case begline: + case endline: case begbuf: case endbuf: case wordbound: case notwordbound: case wordbeg: case wordend: - case push_dummy_failure: - continue; + case push_dummy_failure: + continue; case jump_n: - case pop_failure_jump: + case pop_failure_jump: case maybe_pop_jump: case jump: - case jump_past_alt: + case jump_past_alt: case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR (j, p); - p += j; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; if (j > 0) continue; - - /* Jump backward implies we just went through the body of a - loop and matched nothing. Opcode jumped to should be - `on_failure_jump' or `succeed_n'. Just treat it like an - ordinary jump. For a * loop, it has pushed its failure - point already; if so, discard that as redundant. */ - if ((re_opcode_t) *p != on_failure_jump + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump && (re_opcode_t) *p != succeed_n) continue; - p++; - EXTRACT_NUMBER_AND_INCR (j, p); - p += j; - - /* If what's on the stack is where we are now, pop it. */ - if (!FAIL_STACK_EMPTY () + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () && fail_stack.stack[fail_stack.avail - 1] == p) - fail_stack.avail--; + fail_stack.avail--; - continue; + continue; - case on_failure_jump: - case on_failure_keep_string_jump: + case on_failure_jump: + case on_failure_keep_string_jump: handle_on_failure_jump: - EXTRACT_NUMBER_AND_INCR (j, p); + EXTRACT_NUMBER_AND_INCR (j, p); - /* For some patterns, e.g., `(a?)?', `p+j' here points to the - end of the pattern. We don't want to push such a point, - since when we restore it above, entering the switch will - increment `p' past the end of the pattern. We don't need - to push such a point since we obviously won't find any more - fastmap entries beyond `pend'. Such a pattern can match - the null string, though. */ - if (p + j < pend) - { - if (!PUSH_PATTERN_OP (p + j, fail_stack)) - return -2; - } - else - bufp->can_be_null = 1; + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + return -2; + } + else + bufp->can_be_null = 1; - if (succeed_n_p) - { - EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ - succeed_n_p = false; + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; } - continue; + continue; case succeed_n: - /* Get to the number of times to succeed. */ - p += 2; + /* Get to the number of times to succeed. */ + p += 2; - /* Increment p past the n for when k != 0. */ - EXTRACT_NUMBER_AND_INCR (k, p); - if (k == 0) + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) { - p -= 4; - succeed_n_p = true; /* Spaghetti code alert. */ - goto handle_on_failure_jump; - } - continue; + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; case set_number_at: - p += 4; - continue; + p += 4; + continue; case start_memory: - case stop_memory: + case stop_memory: p += 2; continue; default: - abort (); /* We have listed all the cases. */ - } /* switch *p++ */ + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ /* Getting here means we have found the possible starting - characters for one path of the pattern -- and that the empty - string does not match. We need not follow this path further. - Instead, look at the next alternative (remembered on the - stack), or quit if no more. The test at the top of the loop - does these things. */ + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ path_can_be_null = false; p = pend; } /* while p */ @@ -2824,7 +2824,7 @@ re_search (bufp, string, size, startpos, range, regs) int size, startpos, range; struct re_registers *regs; { - return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, regs, size); } @@ -2832,17 +2832,17 @@ re_search (bufp, string, size, startpos, range, regs) /* Using the compiled pattern in BUFP->buffer, first tries to match the virtual concatenation of STRING1 and STRING2, starting first at index STARTPOS, then at STARTPOS + 1, and so on. - + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. - + RANGE is how far to scan while trying to match. RANGE = 0 means try only at STARTPOS; in general, the last start tried is STARTPOS + RANGE. - + In REGS, return the indices of the virtual concatenation of STRING1 and STRING2 that matched the entire BUFP->buffer and its contained subexpressions. - + Do not consider matching one past the index STOP in the virtual concatenation of STRING1 and STRING2. @@ -2869,7 +2869,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) /* Check for out-of-range STARTPOS. */ if (startpos < 0 || startpos > total_size) return -1; - + /* Fix up RANGE if it might eventually take us outside the virtual concatenation of STRING1 and STRING2. */ if (endpos < -1) @@ -2891,14 +2891,14 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) if (fastmap && !bufp->fastmap_accurate) if (re_compile_fastmap (bufp) == -2) return -2; - + /* Loop through the string, looking for a place to start matching. */ for (;;) - { + { /* If a fastmap is supplied, skip quickly over characters that - cannot be the start of a match. If the pattern can match the - null string, however, we don't need to skip characters; we want - the first null string. */ + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ if (fastmap && startpos < total_size && !bufp->can_be_null) { if (range > 0) /* Searching forwards. */ @@ -2907,29 +2907,29 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) register int lim = 0; int irange = range; - if (startpos < size1 && startpos + range >= size1) - lim = range - (size1 - startpos); + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); d = (startpos >= size1 ? string2 - size1 : string1) + startpos; - - /* Written out as an if-else to avoid testing `translate' - inside the loop. */ + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ if (translate) - while (range > lim - && !fastmap[(unsigned char) + while (range > lim + && !fastmap[(unsigned char) translate[(unsigned char) *d++]]) - range--; + range--; else - while (range > lim && !fastmap[(unsigned char) *d++]) - range--; + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; startpos += irange - range; } else /* Searching backwards. */ { register char c = (size1 == 0 || startpos >= size1 - ? string2[startpos - size1] - : string1[startpos]); + ? string2[startpos - size1] + : string1[startpos]); if (!fastmap[(unsigned char) TRANSLATE (c)]) goto advance; @@ -2938,30 +2938,30 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) /* If can't match the null string, and that's all we have left, fail. */ if (range >= 0 && startpos == total_size && fastmap - && !bufp->can_be_null) + && !bufp->can_be_null) return -1; val = re_match_2 (bufp, string1, size1, string2, size2, - startpos, regs, stop); + startpos, regs, stop); if (val >= 0) return startpos; - + if (val == -2) return -2; advance: - if (!range) - break; - else if (range > 0) - { - range--; - startpos++; - } + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } else - { - range++; - startpos--; - } + { + range++; + startpos--; + } } return -1; } /* re_search_2 */ @@ -2970,16 +2970,16 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) static int bcmp_translate (); static boolean alt_match_null_string_p (), - common_op_match_null_string_p (), - group_match_null_string_p (); + common_op_match_null_string_p (), + group_match_null_string_p (); /* Structure for per-register (a.k.a. per-group) information. This must not be longer than one word, because we push this value onto the failure stack. Other register information, such as the starting and ending positions (which are addresses), and the list of inner groups (which is a bits list) are maintained in separate - variables. - + variables. + We are making a (strictly speaking) nonportable assumption here: that the compiler will pack our bit fields into something that fits into the type of `word', i.e., is something that fits into one item on the @@ -2990,7 +2990,7 @@ typedef union struct { /* This field is one if this group can match the empty string, - zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ #define MATCH_NULL_UNSET_VALUE 3 unsigned match_null_string_p : 2; unsigned is_active : 1; @@ -3013,11 +3013,11 @@ typedef union { \ unsigned r; \ for (r = lowest_active_reg; r <= highest_active_reg; r++) \ - { \ - MATCHED_SOMETHING (reg_info[r]) \ - = EVER_MATCHED_SOMETHING (reg_info[r]) \ - = 1; \ - } \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ } \ while (0) @@ -3043,7 +3043,7 @@ typedef union { \ /* End of string2 => fail. */ \ if (dend == end_match_2) \ - goto fail; \ + goto fail; \ /* End of string1 => advance to string2. */ \ d = string2; \ dend = end_match_2; \ @@ -3053,7 +3053,7 @@ typedef union /* Test if at very beginning or at very end of the virtual concatenation of `string1' and `string2'. If only one string, it's `string2'. */ #define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) -#define AT_STRINGS_END(d) ((d) == end2) +#define AT_STRINGS_END(d) ((d) == end2) /* Test if D points to a character which is word-constituent. We have @@ -3062,7 +3062,7 @@ typedef union string2, look at the last character in string1. */ #define WORDCHAR_P(d) \ (SYNTAX ((d) == end1 ? *string2 \ - : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ == Sword) /* Test if the character before D and the one at D differ with respect @@ -3116,7 +3116,7 @@ re_match (bufp, string, size, pos, regs) int size, pos; struct re_registers *regs; { - return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); + return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); } #endif /* not emacs */ @@ -3125,7 +3125,7 @@ re_match (bufp, string, size, pos, regs) the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 and SIZE2, respectively). We start matching at POS, and stop matching at STOP. - + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we store offsets for the substring each group matched in REGS. See the documentation for exactly how many groups we fill. @@ -3156,7 +3156,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) /* Where we are in the data, and the end of the current string. */ const char *d, *dend; - + /* Where we are in the pattern, and the end of the pattern. */ unsigned char *p = bufp->buffer; register unsigned char *pend = p + bufp->used; @@ -3183,7 +3183,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) return, for use in backreferences. The number here includes an element for register zero. */ unsigned num_regs = bufp->re_nsub + 1; - + /* The currently active registers. */ unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG; unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG; @@ -3213,12 +3213,12 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) register_info_type *reg_info = NULL; /* The following record the register info as found in the above - variables when we find a match better than any we've seen before. + variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = false; const char **best_regstart = NULL, **best_regend = NULL; - + /* Logically, this is `best_regend[0]'. But we don't want to have to allocate space for that if we're not allocating space for anything else (see below). Also, we never need info about register 0 for @@ -3235,13 +3235,13 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) #ifdef DEBUG /* Counts the total number of registers pushed. */ - unsigned num_regs_pushed = 0; + unsigned num_regs_pushed = 0; #endif DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); - + INIT_FAIL_STACK (); - + /* Do not bother to initialize all the register variables if there are no groups in the pattern, as it takes a fair amount of time. If there are groups, we include space for register 0 (the whole @@ -3259,20 +3259,20 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) reg_dummy = REGEX_TALLOC (num_regs, const char *); reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); - if (!(regstart && regend && old_regstart && old_regend && reg_info - && best_regstart && best_regend && reg_dummy && reg_info_dummy)) - { - FREE_VARIABLES (); - return -2; - } + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } } #ifdef REGEX_MALLOC else { /* We must initialize all our variables to NULL, so that - `FREE_VARIABLES' doesn't try to free them. */ + `FREE_VARIABLES' doesn't try to free them. */ regstart = regend = old_regstart = old_regend = best_regstart - = best_regend = reg_dummy = NULL; + = best_regend = reg_dummy = NULL; reg_info = reg_info_dummy = (register_info_type *) NULL; } #endif /* REGEX_MALLOC */ @@ -3283,21 +3283,21 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) FREE_VARIABLES (); return -1; } - + /* Initialize subexpression text positions to -1 to mark ones that no start_memory/stop_memory has been seen for. Also initialize the register information struct. */ for (mcnt = 1; mcnt < num_regs; mcnt++) { - regstart[mcnt] = regend[mcnt] - = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; - + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; IS_ACTIVE (reg_info[mcnt]) = 0; MATCHED_SOMETHING (reg_info[mcnt]) = 0; EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; } - + /* We move `string1' into `string2' if the latter's empty -- but not if `string1' is null. */ if (size2 == 0 && string1 != NULL) @@ -3322,7 +3322,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) end_match_2 = string2 + stop - size1; } - /* `p' scans through the pattern as `d' scans through the data. + /* `p' scans through the pattern as `d' scans through the data. `dend' is the end of the input string that `d' points within. `d' is advanced into the following input string whenever necessary, but this happens before fetching; therefore, at the beginning of the @@ -3344,7 +3344,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) DEBUG_PRINT1 ("The string to match is: `"); DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); DEBUG_PRINT1 ("'\n"); - + /* This loops over pattern commands. It exits by returning from the function if the match is complete, or it drops through if the match fails at this starting point in the input data. */ @@ -3354,140 +3354,140 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) if (p == pend) { /* End of pattern means we might have succeeded. */ - DEBUG_PRINT1 ("end of pattern ... "); - + DEBUG_PRINT1 ("end of pattern ... "); + /* If we haven't matched the entire string, and we want the - longest match, try backtracking. */ - if (d != end_match_2) + longest match, try backtracking. */ + if (d != end_match_2) { - DEBUG_PRINT1 ("backtracking.\n"); - - if (!FAIL_STACK_EMPTY ()) - { /* More failure points to try. */ - boolean same_str_p = (FIRST_STRING_P (match_end) - == MATCHING_IN_FIRST_STRING); + DEBUG_PRINT1 ("backtracking.\n"); - /* If exceeds best match so far, save it. */ - if (!best_regs_set - || (same_str_p && d > match_end) - || (!same_str_p && !MATCHING_IN_FIRST_STRING)) - { - best_regs_set = true; - match_end = d; - - DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); - - for (mcnt = 1; mcnt < num_regs; mcnt++) - { - best_regstart[mcnt] = regstart[mcnt]; - best_regend[mcnt] = regend[mcnt]; - } - } - goto fail; - } + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); - /* If no failure points, don't restore garbage. */ - else if (best_regs_set) - { - restore_best_regs: - /* Restore best match. It may happen that `dend == - end_match_1' while the restored d is in string2. - For example, the pattern `x.*y.*z' against the - strings `x-' and `y-z-', if the two strings are - not consecutive in memory. */ - DEBUG_PRINT1 ("Restoring best registers.\n"); - - d = match_end; - dend = ((d >= string1 && d <= end1) - ? end_match_1 : end_match_2); + /* If exceeds best match so far, save it. */ + if (!best_regs_set + || (same_str_p && d > match_end) + || (!same_str_p && !MATCHING_IN_FIRST_STRING)) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. */ + else if (best_regs_set) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); for (mcnt = 1; mcnt < num_regs; mcnt++) { regstart[mcnt] = best_regstart[mcnt]; regend[mcnt] = best_regend[mcnt]; } - } - } /* d != end_match_2 */ + } + } /* d != end_match_2 */ - DEBUG_PRINT1 ("Accepting match.\n"); + DEBUG_PRINT1 ("Accepting match.\n"); - /* If caller wants register contents data back, do it. */ - if (regs && !bufp->no_sub) + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) { - /* Have the register data arrays been allocated? */ - if (bufp->regs_allocated == REGS_UNALLOCATED) - { /* No. So allocate them with malloc. We need one - extra element beyond `num_regs' for the `-1' marker - GNU code uses. */ - regs->num_regs = MAX (RE_NREGS, num_regs + 1); - regs->start = TALLOC (regs->num_regs, regoff_t); - regs->end = TALLOC (regs->num_regs, regoff_t); - if (regs->start == NULL || regs->end == NULL) - return -2; - bufp->regs_allocated = REGS_REALLOCATE; - } - else if (bufp->regs_allocated == REGS_REALLOCATE) - { /* Yes. If we need more elements than were already - allocated, reallocate them. If we need fewer, just - leave it alone. */ - if (regs->num_regs < num_regs + 1) - { - regs->num_regs = num_regs + 1; - RETALLOC (regs->start, regs->num_regs, regoff_t); - RETALLOC (regs->end, regs->num_regs, regoff_t); - if (regs->start == NULL || regs->end == NULL) - return -2; - } - } - else - assert (bufp->regs_allocated == REGS_FIXED); + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + } + } + else + assert (bufp->regs_allocated == REGS_FIXED); - /* Convert the pointer data in `regstart' and `regend' to - indices. Register zero has to be set differently, - since we haven't kept track of any info for it. */ - if (regs->num_regs > 0) - { - regs->start[0] = pos; - regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 - : d - string2 + size1); - } - - /* Go through the first `min (num_regs, regs->num_regs)' - registers, since that is all we initialized. */ + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 + : d - string2 + size1); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++) { - if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) - regs->start[mcnt] = regs->end[mcnt] = -1; - else - { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]); - regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); - } + regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); + } } - - /* If the regs structure we return has more elements than - were in the pattern, set the extra elements to -1. If - we (re)allocated the registers, this is the case, - because we always allocate enough to have at least one - -1 at the end. */ - for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) - regs->start[mcnt] = regs->end[mcnt] = -1; + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; } /* regs && !bufp->no_sub */ - FREE_VARIABLES (); - DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", - nfailure_points_pushed, nfailure_points_popped, - nfailure_points_pushed - nfailure_points_popped); - DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + FREE_VARIABLES (); + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); - mcnt = d - pos - (MATCHING_IN_FIRST_STRING - ? string1 + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 : string2 - size1); - DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); - return mcnt; - } + return mcnt; + } /* Otherwise match next pattern command. */ #ifdef SWITCH_ENUM_BUG @@ -3496,29 +3496,29 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) switch ((re_opcode_t) *p++) #endif { - /* Ignore these. Used to ignore the n of succeed_n's which - currently have n == 0. */ - case no_op: - DEBUG_PRINT1 ("EXECUTING no_op.\n"); - break; + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; - /* Match the next n pattern characters exactly. The following - byte in the pattern defines n, and the n bytes after that - are the characters to match. */ + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ case exactn: mcnt = *p++; - DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); - /* This is written out as an if-else so we don't waste time - testing `translate' inside the loop. */ - if (translate) + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) { do { PREFETCH (); if (translate[(unsigned char) *d++] != (char) *p++) - goto fail; + goto fail; } while (--mcnt); } @@ -3532,22 +3532,22 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) while (--mcnt); } SET_REGS_MATCHED (); - break; + break; - /* Match any character except possibly a newline or a null. */ + /* Match any character except possibly a newline or a null. */ case anychar: - DEBUG_PRINT1 ("EXECUTING anychar.\n"); + DEBUG_PRINT1 ("EXECUTING anychar.\n"); - PREFETCH (); + PREFETCH (); - if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') - || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) goto fail; - SET_REGS_MATCHED (); - DEBUG_PRINT2 (" Matched `%d'.\n", *d); - d++; + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; break; @@ -3557,13 +3557,13 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) register unsigned char c; boolean not = (re_opcode_t) *(p - 1) == charset_not; - DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); PREFETCH (); c = TRANSLATE (*d); /* The character to match. */ - /* Cast to `unsigned' instead of `unsigned char' in case the - bit list is a full 32 bytes long. */ + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ if (c < (unsigned) (*p * BYTEWIDTH) && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) not = !not; @@ -3571,226 +3571,226 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) p += 1 + *p; if (!not) goto fail; - + SET_REGS_MATCHED (); - d++; + d++; break; } - /* The beginning of a group is represented by start_memory. - The arguments are the register number in the next byte, and the - number of groups inner to this one in the next. The text - matched within the group is recorded (in the internal - registers data structure) under the register number. */ - case start_memory: + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); - /* Find out if this group can match the empty string. */ + /* Find out if this group can match the empty string. */ p1 = p; /* To send to group_match_null_string_p. */ - - if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) - REG_MATCH_NULL_STRING_P (reg_info[*p]) - = group_match_null_string_p (&p1, pend, reg_info); - /* Save the position in the string where we were the last time - we were at this open-group operator in case the group is - operated upon by a repetition operator, e.g., with `(a*)*b' - against `ab'; then we want to ignore where we are now in - the string in case this attempt to match fails. */ - old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) - ? REG_UNSET (regstart[*p]) ? d : regstart[*p] - : regstart[*p]; - DEBUG_PRINT2 (" old_regstart: %d\n", + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", POINTER_TO_OFFSET (old_regstart[*p])); - regstart[*p] = d; + regstart[*p] = d; DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); - IS_ACTIVE (reg_info[*p]) = 1; - MATCHED_SOMETHING (reg_info[*p]) = 0; - - /* This is the new highest active register. */ - highest_active_reg = *p; - - /* If nothing was active before, this is the new lowest active - register. */ - if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) - lowest_active_reg = *p; + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; - /* Move past the register number and inner group count. */ - p += 2; - break; + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + break; - /* The stop_memory opcode represents the end of a group. Its - arguments are the same as start_memory's: the register - number, and the number of inner groups. */ + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ case stop_memory: DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); - - /* We need to save the string position the last time we were at - this close-group operator in case the group is operated - upon by a repetition operator, e.g., with `((a*)*(b*)*)*' - against `aba'; then we want to ignore where we are now in - the string in case this attempt to match fails. */ - old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) - ? REG_UNSET (regend[*p]) ? d : regend[*p] + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] : regend[*p]; - DEBUG_PRINT2 (" old_regend: %d\n", + DEBUG_PRINT2 (" old_regend: %d\n", POINTER_TO_OFFSET (old_regend[*p])); - regend[*p] = d; + regend[*p] = d; DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); - /* This register isn't active anymore. */ - IS_ACTIVE (reg_info[*p]) = 0; - - /* If this was the only register active, nothing is active - anymore. */ - if (lowest_active_reg == highest_active_reg) - { - lowest_active_reg = NO_LOWEST_ACTIVE_REG; - highest_active_reg = NO_HIGHEST_ACTIVE_REG; - } - else - { /* We must scan for the new highest active register, since - it isn't necessarily one less than now: consider - (a(b)c(d(e)f)g). When group 3 ends, after the f), the - new highest active register is 1. */ - unsigned char r = *p - 1; - while (r > 0 && !IS_ACTIVE (reg_info[r])) - r--; - - /* If we end up at register zero, that means that we saved - the registers as the result of an `on_failure_jump', not - a `start_memory', and we jumped to past the innermost - `stop_memory'. For example, in ((.)*) we save - registers 1 and 2 as a result of the *, but when we pop - back to the second ), we are at the stop_memory 1. - Thus, nothing is active. */ + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ if (r == 0) - { - lowest_active_reg = NO_LOWEST_ACTIVE_REG; - highest_active_reg = NO_HIGHEST_ACTIVE_REG; - } - else - highest_active_reg = r; - } - - /* If just failed to match something this time around with a - group that's operated on by a repetition operator, try to - force exit from the ``loop'', and restore the register - information for this group that we had before trying this - last match. */ - if ((!MATCHED_SOMETHING (reg_info[*p]) - || (re_opcode_t) p[-3] == start_memory) - && (p + 2) < pend) - { - boolean is_a_jump_n = false; - - p1 = p + 2; - mcnt = 0; - switch ((re_opcode_t) *p1++) - { - case jump_n: + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || (re_opcode_t) p[-3] == start_memory) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: is_a_jump_n = true; - case pop_failure_jump: + case pop_failure_jump: case maybe_pop_jump: case jump: case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p1); + EXTRACT_NUMBER_AND_INCR (mcnt, p1); if (is_a_jump_n) p1 += 2; - break; - - default: - /* do nothing */ ; - } + break; + + default: + /* do nothing */ ; + } p1 += mcnt; - - /* If the next operation is a jump backwards in the pattern - to an on_failure_jump right before the start_memory - corresponding to this stop_memory, exit from the loop - by forcing a failure after pushing on the stack the - on_failure_jump's jump in the pattern, and d. */ - if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump - && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) { - /* If this group ever matched anything, then restore - what its registers were before trying this last - failed match, e.g., with `(a*)*b' against `ab' for - regstart[1], and, e.g., with `((a*)*(b*)*)*' - against `aba' for regend[3]. - - Also restore the registers for inner groups for, - e.g., `((a*)(b*))*' against `aba' (register 3 would - otherwise get trashed). */ - - if (EVER_MATCHED_SOMETHING (reg_info[*p])) + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) { - unsigned r; - - EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; - + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + /* Restore this and inner groups' (if any) registers. */ - for (r = *p; r < *p + *(p + 1); r++) - { - regstart[r] = old_regstart[r]; + for (r = *p; r < *p + *(p + 1); r++) + { + regstart[r] = old_regstart[r]; - /* xx why this test? */ - if ((int) old_regend[r] >= (int) regstart[r]) - regend[r] = old_regend[r]; - } - } + /* xx why this test? */ + if ((int) old_regend[r] >= (int) regstart[r]) + regend[r] = old_regend[r]; + } + } p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); - goto fail; - } - } - - /* Move past the register number and the inner group count. */ - p += 2; - break; + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; /* \ has been turned into a `duplicate' command which is - followed by the numeric value of as the register number. */ - case duplicate: + followed by the numeric value of as the register number. */ + case duplicate: { register const char *d2, *dend2; int regno = *p++; /* Get which register to match against. */ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); /* Can't back reference a group which we've never matched. */ - if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) - goto fail; - - /* Where in input to try to start matching. */ - d2 = regstart[regno]; - - /* Where to stop matching; if both the place to start and - the place to stop matching are in the same string, then - set to the place to stop, otherwise, for now have to use - the end of the first string. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; - dend2 = ((FIRST_STRING_P (regstart[regno]) + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) == FIRST_STRING_P (regend[regno])) ? regend[regno] : end_match_1); for (;;) { /* If necessary, advance to next segment in register - contents. */ + contents. */ while (d2 == dend2) { if (dend2 == end_match_2) break; if (dend2 == regend[regno]) break; - /* End of string1 => advance to string2. */ - d2 = string2; - dend2 = regend[regno]; + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; } /* At end of register contents => success */ if (d2 == dend2) break; @@ -3800,17 +3800,17 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) /* How many characters left in this segment to match. */ mcnt = dend - d; - + /* Want how many consecutive characters we can match in - one shot, so, if necessary, adjust the count. */ - if (mcnt > dend2 - d2) + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) mcnt = dend2 - d2; - + /* Compare that many; failure if mismatch, else move - past them. */ - if (translate - ? bcmp_translate (d, d2, mcnt, translate) - : bcmp (d, d2, mcnt)) + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : bcmp (d, d2, mcnt)) goto fail; d += mcnt, d2 += mcnt; } @@ -3818,157 +3818,157 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) break; - /* begline matches the empty string at the beginning of the string - (unless `not_bol' is set in `bufp'), and, if - `newline_anchor' is set, after newlines. */ + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ case begline: - DEBUG_PRINT1 ("EXECUTING begline.\n"); - - if (AT_STRINGS_BEG (d)) - { - if (!bufp->not_bol) break; - } - else if (d[-1] == '\n' && bufp->newline_anchor) - { - break; - } - /* In all other cases, we fail. */ - goto fail; + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; - /* endline is the dual of begline. */ + /* endline is the dual of begline. */ case endline: - DEBUG_PRINT1 ("EXECUTING endline.\n"); + DEBUG_PRINT1 ("EXECUTING endline.\n"); - if (AT_STRINGS_END (d)) - { - if (!bufp->not_eol) break; - } - - /* We have to ``prefetch'' the next character. */ - else if ((d == end1 ? *string2 : *d) == '\n' - && bufp->newline_anchor) - { - break; - } - goto fail; + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; /* Match at the very beginning of the data. */ - case begbuf: - DEBUG_PRINT1 ("EXECUTING begbuf.\n"); - if (AT_STRINGS_BEG (d)) - break; - goto fail; + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; /* Match at the very end of the data. */ - case endbuf: - DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); if (AT_STRINGS_END (d)) break; - goto fail; + goto fail; - /* on_failure_keep_string_jump is used to optimize `.*\n'. It - pushes NULL as the value for the string on the stack. Then - `pop_failure_point' will keep the current value for the - string, instead of restoring it. To see why, consider - matching `foo\nbar' against `.*\n'. The .* matches the foo; - then the . fails against the \n. But the next thing we want - to do is match the \n against the \n; if we restored the - string value, we would be back at the foo. - - Because this is used only in specific cases, we don't need to - check all the things that `on_failure_jump' does, to make - sure the right things get saved on the stack. Hence we don't - share its code. The only reason to push anything on the - stack at all is that otherwise we would have to change - `anychar's code to do something besides goto fail in this - case; that seems worse than this. */ - case on_failure_keep_string_jump: - DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); - - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. - PUSH_FAILURE_POINT (p + mcnt, NULL, -2); - break; + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; /* Uses of on_failure_jump: - - Each alternative starts with an on_failure_jump that points - to the beginning of the next alternative. Each alternative - except the last ends with a jump that in effect jumps past - the rest of the alternatives. (They really jump to the - ending jump of the following alternative, because tensioning - these jumps is a hassle.) - Repeats start with an on_failure_jump that points past both - the repetition text and either the following jump or - pop_failure_jump back to this on_failure_jump. */ + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ case on_failure_jump: - on_failure: - DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); - /* If this on_failure_jump comes right before a group (i.e., - the original * applied to a group), save the information - for that group and all inner ones, so that if we fail back - to this point, the group's information will be correct. - For example, in \(a*\)*\1, we need the preceding group, - and in \(\(a*\)b*\)\2, we need the inner group. */ + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(\(a*\)b*\)\2, we need the inner group. */ - /* We can't use `p' to check ahead because we push - a failure point to `p + mcnt' after we do this. */ - p1 = p; + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; - /* We need to skip no_op's before we look for the - start_memory in case this on_failure_jump is happening as - the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 - against aba. */ - while (p1 < pend && (re_opcode_t) *p1 == no_op) - p1++; + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; - if (p1 < pend && (re_opcode_t) *p1 == start_memory) - { - /* We have a new highest active register now. This will - get reset at the start_memory we are about to get to, - but we will have saved all the registers relevant to - this repetition op, as described above. */ - highest_active_reg = *(p1 + 1) + *(p1 + 2); - if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) - lowest_active_reg = *(p1 + 1); - } + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } - DEBUG_PRINT1 (":\n"); - PUSH_FAILURE_POINT (p + mcnt, d, -2); - break; + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; - /* A smart repeat ends with `maybe_pop_jump'. + /* A smart repeat ends with `maybe_pop_jump'. We change it to either `pop_failure_jump' or `jump'. */ - case maybe_pop_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); - { + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { register unsigned char *p2 = p; - /* Compare the beginning of the repeat with what in the - pattern follows its end. If we can establish that there - is nothing that they would both match, i.e., that we - would have to backtrack because of (as in, e.g., `a*a') - then we can change to pop_failure_jump, because we'll - never have to backtrack. - - This is not true in the case of alternatives: in - `(a|ab)*' we do need to backtrack to the `ab' alternative - (e.g., if the string was `ab'). But instead of trying to - detect that here, the alternative has put on a dummy - failure point which is what we will end up popping. */ + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ /* Skip over open/close-group commands. */ while (p2 + 2 < pend @@ -3976,50 +3976,50 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) || (re_opcode_t) *p2 == start_memory)) p2 += 3; /* Skip over args, too. */ - /* If we're at the end of the pattern, we can change. */ - if (p2 == pend) + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) { /* Consider what happens when matching ":\(.*\)" against ":/". I don't really understand this code yet. */ - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 - (" End of pattern: change to `pop_failure_jump'.\n"); - } + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } - else if ((re_opcode_t) *p2 == exactn + else if ((re_opcode_t) *p2 == exactn || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) { register unsigned char c - = *p2 == (unsigned char) endline ? '\n' : p2[2]; + = *p2 == (unsigned char) endline ? '\n' : p2[2]; p1 = p + mcnt; - /* p1[0] ... p1[2] are the `on_failure_jump' corresponding - to the `maybe_finalize_jump' of this case. Examine what - follows. */ - if ((re_opcode_t) p1[3] == exactn && p1[5] != c) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", - c, p1[5]); - } - + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + else if ((re_opcode_t) p1[3] == charset || (re_opcode_t) p1[3] == charset_not) { int not = (re_opcode_t) p1[3] == charset_not; - + if (c < (unsigned char) (p1[4] * BYTEWIDTH) && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) not = !not; - /* `not' is equal to 1 if c would match, which means - that we can't change to pop_failure_jump. */ + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ if (!not) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); - } + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } } } } @@ -4027,235 +4027,235 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) if ((re_opcode_t) p[-1] != pop_failure_jump) { p[-1] = (unsigned char) jump; - DEBUG_PRINT1 (" Match => jump.\n"); + DEBUG_PRINT1 (" Match => jump.\n"); goto unconditional_jump; } - /* Note fall through. */ + /* Note fall through. */ /* The end of a simple repeat has a pop_failure_jump back to - its matching on_failure_jump, where the latter will push a - failure point. The pop_failure_jump takes off failure - points put on by this pop_failure_jump's matching - on_failure_jump; we got through the pattern to here from the - matching on_failure_jump, so didn't fail. */ - case pop_failure_jump: - { - /* We need to pass separate storage for the lowest and - highest registers, even though we don't care about the - actual values. Otherwise, we will restore only one - register from the stack, since lowest will == highest in - `pop_failure_point'. */ - unsigned dummy_low_reg, dummy_high_reg; - unsigned char *pdummy; - const char *sdummy; + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + unsigned dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; - DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); - POP_FAILURE_POINT (sdummy, pdummy, - dummy_low_reg, dummy_high_reg, - reg_dummy, reg_dummy, reg_info_dummy); - } - /* Note fall through. */ + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ - - /* Unconditionally jump (without popping any failure points). */ - case jump: + + /* Unconditionally jump (without popping any failure points). */ + case jump: unconditional_jump: EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ - DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); p += mcnt; /* Do the jump. */ - DEBUG_PRINT2 ("(to 0x%x).\n", p); + DEBUG_PRINT2 ("(to 0x%x).\n", p); break; - - /* We need this opcode so we can detect where alternatives end - in `group_match_null_string_p' et al. */ - case jump_past_alt: - DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); - goto unconditional_jump; + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; - /* Normally, the on_failure_jump pushes a failure point, which - then gets popped at pop_failure_jump. We will end up at - pop_failure_jump, also, and with a pattern of, say, `a+', we - are skipping over the on_failure_jump, so we have to push - something meaningless for pop_failure_jump to pop. */ - case dummy_failure_jump: - DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); - /* It doesn't matter what we push for the string here. What - the code at `fail' tests is the value for the pattern. */ - PUSH_FAILURE_POINT (0, 0, -2); - goto unconditional_jump; + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (0, 0, -2); + goto unconditional_jump; - /* At the end of an alternative, we need to push a dummy failure - point in case we are followed by a `pop_failure_jump', because - we don't want the failure point for the alternative to be - popped. For example, matching `(a|ab)*' against `aab' - requires that we match the `ab' alternative. */ - case push_dummy_failure: - DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); - /* See comments just above at `dummy_failure_jump' about the - two zeroes. */ - PUSH_FAILURE_POINT (0, 0, -2); - break; + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (0, 0, -2); + break; - /* Have to succeed matching what follows at least n times. - After that, handle like `on_failure_jump'. */ - case succeed_n: - EXTRACT_NUMBER (mcnt, p + 2); - DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); - assert (mcnt >= 0); - /* Originally, this is how many times we HAVE to succeed. */ - if (mcnt > 0) - { - mcnt--; + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; p += 2; - STORE_NUMBER_AND_INCR (p, mcnt); - DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); - } + STORE_NUMBER_AND_INCR (p, mcnt); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); + } else if (mcnt == 0) - { - DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); + { + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); p[2] = (unsigned char) no_op; - p[3] = (unsigned char) no_op; - goto on_failure; - } - break; - - case jump_n: - EXTRACT_NUMBER (mcnt, p + 2); - DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; - /* Originally, this is how many times we CAN jump. */ - if (mcnt) - { - mcnt--; - STORE_NUMBER (p + 2, mcnt); - goto unconditional_jump; - } - /* If don't have to jump any more, skip over the rest of command. */ - else - p += 4; - break; - case set_number_at: { - DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); - EXTRACT_NUMBER_AND_INCR (mcnt, p); - p1 = p + mcnt; - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); STORE_NUMBER (p1, mcnt); - break; - } - - case wordbound: - DEBUG_PRINT1 ("EXECUTING wordbound.\n"); - if (AT_WORD_BOUNDARY (d)) break; - goto fail; + } + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; case notwordbound: - DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); if (AT_WORD_BOUNDARY (d)) goto fail; - break; + break; case wordbeg: - DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) break; - goto fail; + goto fail; case wordend: - DEBUG_PRINT1 ("EXECUTING wordend.\n"); + DEBUG_PRINT1 ("EXECUTING wordend.\n"); if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) - && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) break; - goto fail; + goto fail; #ifdef emacs #ifdef emacs19 - case before_dot: - DEBUG_PRINT1 ("EXECUTING before_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) >= point) - goto fail; - break; - - case at_dot: - DEBUG_PRINT1 ("EXECUTING at_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) != point) - goto fail; - break; - - case after_dot: - DEBUG_PRINT1 ("EXECUTING after_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) <= point) - goto fail; - break; + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; #else /* not emacs19 */ case at_dot: - DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point) goto fail; break; #endif /* not emacs19 */ case syntaxspec: - DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); mcnt = *p++; goto matchsyntax; - case wordchar: - DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); mcnt = (int) Sword; - matchsyntax: + matchsyntax: PREFETCH (); if (SYNTAX (*d++) != (enum syntaxcode) mcnt) - goto fail; - SET_REGS_MATCHED (); + goto fail; + SET_REGS_MATCHED (); break; case notsyntaxspec: - DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); mcnt = *p++; goto matchnotsyntax; - case notwordchar: - DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); mcnt = (int) Sword; - matchnotsyntax: + matchnotsyntax: PREFETCH (); if (SYNTAX (*d++) == (enum syntaxcode) mcnt) - goto fail; + goto fail; SET_REGS_MATCHED (); - break; + break; #else /* not emacs */ case wordchar: - DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); PREFETCH (); - if (!WORDCHAR_P (d)) - goto fail; + if (!WORDCHAR_P (d)) + goto fail; SET_REGS_MATCHED (); - d++; + d++; break; - + case notwordchar: - DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); PREFETCH (); if (WORDCHAR_P (d)) - goto fail; - SET_REGS_MATCHED (); - d++; + goto fail; + SET_REGS_MATCHED (); + d++; break; #endif /* not emacs */ - - default: - abort (); + + default: + abort (); } continue; /* Successfully executed one pattern command; keep going. */ @@ -4264,49 +4264,49 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) fail: if (!FAIL_STACK_EMPTY ()) { /* A restart point is known. Restore to that state. */ - DEBUG_PRINT1 ("\nFAIL:\n"); - POP_FAILURE_POINT (d, p, - lowest_active_reg, highest_active_reg, - regstart, regend, reg_info); + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); - /* If this failure point is a dummy, try the next one. */ - if (!p) + /* If this failure point is a dummy, try the next one. */ + if (!p) goto fail; - /* If we failed to the end of the pattern, don't examine *p. */ + /* If we failed to the end of the pattern, don't examine *p. */ assert (p <= pend); - if (p < pend) - { - boolean is_a_jump_n = false; - - /* If failed to a backwards jump that's part of a repetition - loop, need to pop this failure point and use the next one. */ - switch ((re_opcode_t) *p) - { - case jump_n: - is_a_jump_n = true; - case maybe_pop_jump: - case pop_failure_jump: - case jump: - p1 = p + 1; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; + if (p < pend) + { + boolean is_a_jump_n = false; - if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) - || (!is_a_jump_n - && (re_opcode_t) *p1 == on_failure_jump)) - goto fail; - break; - default: - /* do nothing */ ; - } - } + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; - if (d >= string1 && d <= end1) + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) dend = end_match_1; - } + } else - break; /* Matching at this starting point really fails. */ + break; /* Matching at this starting point really fails. */ } /* for (;;) */ if (best_regs_set) @@ -4321,10 +4321,10 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) /* We are passed P pointing to a register number after a start_memory. - + Return true if the pattern up to the corresponding stop_memory can match the empty string, and false otherwise. - + If we find the matching stop_memory, sets P to point to one past its number. Otherwise, sets P to an undefined byte less than or equal to END. @@ -4338,97 +4338,97 @@ group_match_null_string_p (p, end, reg_info) int mcnt; /* Point to after the args to the start_memory. */ unsigned char *p1 = *p + 2; - + while (p1 < end) { /* Skip over opcodes that can match nothing, and return true or false, as appropriate, when we get to one that can't, or to the - matching stop_memory. */ - + matching stop_memory. */ + switch ((re_opcode_t) *p1) - { - /* Could be either a loop or a series of alternatives. */ - case on_failure_jump: - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - - /* If the next operation is not a jump backwards in the + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the pattern. */ if (mcnt >= 0) { - /* Go through the on_failure_jumps of the alternatives, - seeing if any of the alternatives cannot match nothing. - The last alternative starts with only a jump, - whereas the rest start with on_failure_jump and end - with a jump, e.g., here is the pattern for `a|b|c': + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': - /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 - /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 - /exactn/1/c + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c - So, we have to first go through the first (n-1) - alternatives and then deal with the last one separately. */ + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ - /* Deal with the first (n-1) alternatives, which start - with an on_failure_jump (see above) that jumps to right - past a jump_past_alt. */ + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ - while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) - { - /* `mcnt' holds how many bytes long the alternative - is, including the ending `jump_past_alt' and - its number. */ + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ - if (!alt_match_null_string_p (p1, p1 + mcnt - 3, - reg_info)) - return false; + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; - /* Move to right after this alternative, including the + /* Move to right after this alternative, including the jump_past_alt. */ - p1 += mcnt; + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; - /* Break if it's the beginning of an n-th alternative - that doesn't begin with an on_failure_jump. */ - if ((re_opcode_t) *p1 != on_failure_jump) - break; - /* Still have to check that it's not an n-th alternative that starts with an on_failure_jump. */ p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) - { + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { /* Get to the beginning of the n-th alternative. */ - p1 -= 3; - break; - } - } + p1 -= 3; + break; + } + } - /* Deal with the last alternative: go back and get number - of the `jump_past_alt' just before it. `mcnt' contains - the length of the alternative. */ - EXTRACT_NUMBER (mcnt, p1 - 2); + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); - if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) - return false; + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; - p1 += mcnt; /* Get past the n-th alternative. */ - } /* if mcnt > 0 */ - break; + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; - - case stop_memory: + + case stop_memory: assert (p1[1] == **p); - *p = p1 + 2; - return true; + *p = p1 + 2; + return true; - - default: - if (!common_op_match_null_string_p (&p1, end, reg_info)) - return false; - } + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } } /* while p1 < end */ return false; @@ -4438,7 +4438,7 @@ group_match_null_string_p (p, end, reg_info) /* Similar to group_match_null_string_p, but doesn't deal with alternatives: It expects P to be the first byte of a single alternative and END one byte past the last. The alternative can contain groups. */ - + static boolean alt_match_null_string_p (p, end, reg_info) unsigned char *p, *end; @@ -4446,25 +4446,25 @@ alt_match_null_string_p (p, end, reg_info) { int mcnt; unsigned char *p1 = p; - + while (p1 < end) { - /* Skip over opcodes that can match nothing, and break when we get - to one that can't. */ - + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + switch ((re_opcode_t) *p1) - { + { /* It's a loop. */ - case on_failure_jump: - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - break; - - default: - if (!common_op_match_null_string_p (&p1, end, reg_info)) - return false; - } + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } } /* while p1 < end */ return true; @@ -4472,8 +4472,8 @@ alt_match_null_string_p (p, end, reg_info) /* Deals with the ops common to group_match_null_string_p and - alt_match_null_string_p. - + alt_match_null_string_p. + Sets P to one after the op and its arguments, if any. */ static boolean @@ -4508,44 +4508,44 @@ common_op_match_null_string_p (p, end, reg_info) reg_no = *p1; assert (reg_no > 0 && reg_no <= MAX_REGNUM); ret = group_match_null_string_p (&p1, end, reg_info); - + /* Have to set this here in case we're checking a group which - contains a group and a back reference to it. */ + contains a group and a back reference to it. */ if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) - REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; if (!ret) - return false; + return false; break; - + /* If this is an optimized succeed_n for zero times, make the jump. */ case jump: EXTRACT_NUMBER_AND_INCR (mcnt, p1); if (mcnt >= 0) - p1 += mcnt; + p1 += mcnt; else - return false; + return false; break; case succeed_n: /* Get to the number of times to succeed. */ - p1 += 2; + p1 += 2; EXTRACT_NUMBER_AND_INCR (mcnt, p1); if (mcnt == 0) - { - p1 -= 4; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - } + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } else - return false; + return false; break; - case duplicate: + case duplicate: if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) - return false; + return false; break; case set_number_at: @@ -4563,7 +4563,7 @@ common_op_match_null_string_p (p, end, reg_info) /* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN bytes; nonzero otherwise. */ - + static int bcmp_translate( unsigned char *s1, @@ -4586,10 +4586,10 @@ bcmp_translate( /* re_compile_pattern is the GNU regular expression compiler: it compiles PATTERN (of length SIZE) and puts the result in BUFP. Returns 0 if the pattern was valid, otherwise an error string. - + Assumes the `allocated' (and perhaps `buffer') and `translate' fields are set in BUFP on entry. - + We call regex_compile to do the actual compilation. */ const char * @@ -4599,23 +4599,23 @@ re_compile_pattern (pattern, length, bufp) struct re_pattern_buffer *bufp; { reg_errcode_t ret; - + /* GNU code is written to assume at least RE_NREGS registers will be set (and at least one extra will be -1). */ bufp->regs_allocated = REGS_UNALLOCATED; - + /* And GNU code determines whether or not to get register information by passing null for the REGS argument to re_match, etc., not by setting no_sub. */ bufp->no_sub = 0; - + /* Match anchors at newline. */ bufp->newline_anchor = 1; - + ret = regex_compile (pattern, length, re_syntax_options, bufp); return re_error_msg[(int) ret]; -} +} /* Entry points compatible with 4.2 BSD regex library. We don't define them if this is an Emacs or POSIX compilation. */ @@ -4630,7 +4630,7 @@ re_comp (s) const char *s; { reg_errcode_t ret; - + if (!s) { if (!re_comp_buf.buffer) @@ -4642,7 +4642,7 @@ re_comp (s) { re_comp_buf.buffer = (unsigned char *) malloc (200); if (re_comp_buf.buffer == NULL) - return "Memory exhausted"; + return "Memory exhausted"; re_comp_buf.allocated = 200; re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); @@ -4657,7 +4657,7 @@ re_comp (s) re_comp_buf.newline_anchor = 1; ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); - + /* Yes, we're discarding `const' here. */ return (char *) re_error_msg[(int) ret]; } @@ -4714,7 +4714,7 @@ re_exec (s) int regcomp (preg, pattern, cflags) regex_t *preg; - const char *pattern; + const char *pattern; int cflags; { reg_errcode_t ret; @@ -4725,24 +4725,24 @@ regcomp (preg, pattern, cflags) /* regex_compile will allocate the space for the compiled pattern. */ preg->buffer = 0; preg->allocated = 0; - + /* Don't bother to use a fastmap when searching. This simplifies the REG_NEWLINE case: if we used a fastmap, we'd have to put all the characters after newlines into the fastmap. This way, we just try every character. */ preg->fastmap = 0; - + if (cflags & REG_ICASE) { unsigned i; - + preg->translate = (char *) malloc (CHAR_SET_SIZE); if (preg->translate == NULL) - return (int) REG_ESPACE; + return (int) REG_ESPACE; /* Map uppercase characters to corresponding lowercase ones. */ for (i = 0; i < CHAR_SET_SIZE; i++) - preg->translate[i] = ISUPPER (i) ? tolower (i) : i; + preg->translate[i] = ISUPPER (i) ? tolower (i) : i; } else preg->translate = NULL; @@ -4760,38 +4760,38 @@ regcomp (preg, pattern, cflags) preg->no_sub = !!(cflags & REG_NOSUB); - /* POSIX says a null character in the pattern terminates it, so we + /* POSIX says a null character in the pattern terminates it, so we can use strlen here in compiling the pattern. */ ret = regex_compile (pattern, strlen (pattern), syntax, preg); - + /* POSIX doesn't distinguish between an unmatched open-group and an unmatched close-group: both are REG_EPAREN. */ if (ret == REG_ERPAREN) ret = REG_EPAREN; - + return (int) ret; } /* regexec searches for a given pattern, specified by PREG, in the string STRING. - + If NMATCH is zero or REG_NOSUB was set in the cflags argument to `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at least NMATCH elements, and we set them to the offsets of the corresponding matched substrings. - + EFLAGS specifies `execution flags' which affect matching: if REG_NOTBOL is set, then ^ does not match at the beginning of the string; if REG_NOTEOL is set, then $ does not match at the end. - + We return 0 if we find a match and REG_NOMATCH if not. */ int regexec (preg, string, nmatch, pmatch, eflags) const regex_t *preg; - const char *string; - size_t nmatch; - regmatch_t pmatch[]; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; int eflags; { int ret; @@ -4801,42 +4801,42 @@ regexec (preg, string, nmatch, pmatch, eflags) boolean want_reg_info = !preg->no_sub && nmatch > 0; private_preg = *preg; - + private_preg.not_bol = !!(eflags & REG_NOTBOL); private_preg.not_eol = !!(eflags & REG_NOTEOL); - + /* The user has told us exactly how many registers to return information about, via `nmatch'. We have to pass that on to the matching routines. */ private_preg.regs_allocated = REGS_FIXED; - + if (want_reg_info) { regs.num_regs = nmatch; regs.start = TALLOC (nmatch, regoff_t); regs.end = TALLOC (nmatch, regoff_t); if (regs.start == NULL || regs.end == NULL) - return (int) REG_NOMATCH; + return (int) REG_NOMATCH; } /* Perform the searching operation. */ ret = re_search (&private_preg, string, len, - /* start: */ 0, /* range: */ len, - want_reg_info ? ®s : (struct re_registers *) 0); - + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + /* Copy the register information to the POSIX structure. */ if (want_reg_info) { if (ret >= 0) - { - unsigned r; + { + unsigned r; - for (r = 0; r < nmatch; r++) - { - pmatch[r].rm_so = regs.start[r]; - pmatch[r].rm_eo = regs.end[r]; - } - } + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } /* If we needed the temporary register info, free the space now. */ free (regs.start); @@ -4863,7 +4863,7 @@ regerror (errcode, preg, errbuf, errbuf_size) if (errcode < 0 || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) - /* Only error codes returned by the rest of the code should be passed + /* Only error codes returned by the rest of the code should be passed to this routine. If we are given anything else, or if other regex code generates an invalid error code, then the program has a bug. Dump core so we can fix it. */ @@ -4877,16 +4877,16 @@ regerror (errcode, preg, errbuf, errbuf_size) msg = "Success"; msg_size = strlen (msg) + 1; /* Includes the null. */ - + if (errbuf_size != 0) { if (msg_size > errbuf_size) - { - strncpy (errbuf, msg, errbuf_size - 1); - errbuf[errbuf_size - 1] = 0; - } + { + strncpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; + } else - strcpy (errbuf, msg); + strcpy (errbuf, msg); } return msg_size; @@ -4902,7 +4902,7 @@ regfree (preg) if (preg->buffer != NULL) free (preg->buffer); preg->buffer = NULL; - + preg->allocated = 0; preg->used = 0; diff --git a/compat/regex.h b/compat/regex.h index 408dd21034..6eb64f1402 100644 --- a/compat/regex.h +++ b/compat/regex.h @@ -42,7 +42,7 @@ typedef unsigned reg_syntax_t; #define RE_BACKSLASH_ESCAPE_IN_LISTS (1) /* If this bit is not set, then + and ? are operators, and \+ and \? are - literals. + literals. If set, then \+ and \? are operators and + and ? are literals. */ #define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) @@ -55,10 +55,10 @@ typedef unsigned reg_syntax_t; /* If this bit is set, then ^ and $ are always anchors (outside bracket expressions, of course). If this bit is not set, then it depends: - ^ is an anchor if it is at the beginning of a regular - expression or after an open-group or an alternation operator; - $ is an anchor if it is at the end of a regular expression, or - before a close-group or an alternation operator. + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because POSIX draft 11.2 says that * etc. in leading positions is undefined. @@ -69,7 +69,7 @@ typedef unsigned reg_syntax_t; /* If this bit is set, then special characters are always special regardless of where they are in the pattern. If this bit is not set, then special characters are special only in - some contexts; otherwise they are ordinary. Specifically, + some contexts; otherwise they are ordinary. Specifically, * + ? and intervals are only special when not after the beginning, open-group, or alternation operator. */ #define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) @@ -91,7 +91,7 @@ typedef unsigned reg_syntax_t; #define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) /* If this bit is set, either \{...\} or {...} defines an - interval, depending on RE_NO_BK_BRACES. + interval, depending on RE_NO_BK_BRACES. If not set, \{, \}, {, and } are literals. */ #define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) @@ -116,7 +116,7 @@ typedef unsigned reg_syntax_t; If not set, then \ is a back-reference. */ #define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) -/* If this bit is set, then | is an alternation operator, and \| is literal. +/* If this bit is set, then | is an alternation operator, and \| is literal. If not set, then \| is an alternation operator, and | is literal. */ #define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) @@ -138,7 +138,7 @@ extern reg_syntax_t re_syntax_options; /* Define combinations of the above bits for the standard possibilities. (The [[[ comments delimit what gets put into the Texinfo file, so - don't delete them!) */ + don't delete them!) */ /* [[[begin syntaxes]]] */ #define RE_SYNTAX_EMACS 0 @@ -205,7 +205,7 @@ extern reg_syntax_t re_syntax_options; #ifdef RE_DUP_MAX #undef RE_DUP_MAX #endif -#define RE_DUP_MAX ((1 << 15) - 1) +#define RE_DUP_MAX ((1 << 15) - 1) /* POSIX `cflags' bits (i.e., information for `regcomp'). */ @@ -217,7 +217,7 @@ extern reg_syntax_t re_syntax_options; /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ #define REG_ICASE (REG_EXTENDED << 1) - + /* If this bit is set, then anchors do not match at newline characters in the string. If not set, then anchors do match at newlines. */ @@ -256,7 +256,7 @@ typedef enum REG_EESCAPE, /* Trailing backslash. */ REG_ESUBREG, /* Invalid back reference. */ REG_EBRACK, /* Unmatched left bracket. */ - REG_EPAREN, /* Parenthesis imbalance. */ + REG_EPAREN, /* Parenthesis imbalance. */ REG_EBRACE, /* Unmatched \{. */ REG_BADBR, /* Invalid contents of \{\}. */ REG_ERANGE, /* Invalid range end. */ @@ -279,65 +279,65 @@ struct re_pattern_buffer { /* [[[begin pattern_buffer]]] */ /* Space that holds the compiled pattern. It is declared as - `unsigned char *' because its elements are - sometimes used as array indexes. */ + `unsigned char *' because its elements are + sometimes used as array indexes. */ unsigned char *buffer; /* Number of bytes to which `buffer' points. */ unsigned long allocated; /* Number of bytes actually used in `buffer'. */ - unsigned long used; + unsigned long used; - /* Syntax setting with which the pattern was compiled. */ + /* Syntax setting with which the pattern was compiled. */ reg_syntax_t syntax; - /* Pointer to a fastmap, if any, otherwise zero. re_search uses - the fastmap, if there is one, to skip over impossible - starting points for matches. */ + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ char *fastmap; - /* Either a translate table to apply to all characters before - comparing them, or zero for no translation. The translation - is applied to a pattern when it is compiled and to a string - when it is matched. */ + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ char *translate; /* Number of subexpressions found by the compiler. */ size_t re_nsub; - /* Zero if this pattern cannot match the empty string, one else. - Well, in truth it's used only in `re_search_2', to see - whether or not we should use the fastmap, so we don't set - this absolutely perfectly; see `re_compile_fastmap' (the - `duplicate' case). */ + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ unsigned can_be_null : 1; - /* If REGS_UNALLOCATED, allocate space in the `regs' structure - for `max (RE_NREGS, re_nsub + 1)' groups. - If REGS_REALLOCATE, reallocate space if necessary. - If REGS_FIXED, use what's there. */ + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ #define REGS_UNALLOCATED 0 #define REGS_REALLOCATE 1 #define REGS_FIXED 2 unsigned regs_allocated : 2; - /* Set to zero when `regex_compile' compiles a pattern; set to one - by `re_compile_fastmap' if it updates the fastmap. */ + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ unsigned fastmap_accurate : 1; - /* If set, `re_match_2' does not return information about - subexpressions. */ + /* If set, `re_match_2' does not return information about + subexpressions. */ unsigned no_sub : 1; - /* If set, a beginning-of-line anchor doesn't match at the - beginning of the string. */ + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ unsigned not_bol : 1; - /* Similarly for an end-of-line anchor. */ + /* Similarly for an end-of-line anchor. */ unsigned not_eol : 1; - /* If true, an anchor at a newline matches. */ + /* If true, an anchor at a newline matches. */ unsigned newline_anchor : 1; /* [[[end pattern_buffer]]] */ @@ -408,7 +408,7 @@ extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); BUFFER. Return NULL if successful, and an error string if not. */ extern const char *re_compile_pattern _RE_ARGS ((const char *pattern, int length, - struct re_pattern_buffer *buffer)); + struct re_pattern_buffer *buffer)); /* Compile a fastmap for the compiled pattern in BUFFER; used to @@ -424,29 +424,29 @@ extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); information in REGS (if REGS and BUFFER->no_sub are nonzero). */ extern int re_search _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, int range, struct re_registers *regs)); + int length, int start, int range, struct re_registers *regs)); /* Like `re_search', but search in the concatenation of STRING1 and STRING2. Also, stop searching at index START + STOP. */ extern int re_search_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, int range, struct re_registers *regs, int stop)); + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); /* Like `re_search', but return how many characters in STRING the regexp in BUFFER matched, starting at position START. */ extern int re_match _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, struct re_registers *regs)); + int length, int start, struct re_registers *regs)); /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ -extern int re_match_2 +extern int re_match_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, struct re_registers *regs, int stop)); + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); /* Set REGS to hold NUM_REGS registers, storing them in STARTS and @@ -463,7 +463,7 @@ extern int re_match_2 freeing the old data. */ extern void re_set_registers _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, - unsigned num_regs, regoff_t *starts, regoff_t *ends)); + unsigned num_regs, regoff_t *starts, regoff_t *ends)); /* 4.2 bsd compatibility. */ extern char *re_comp _RE_ARGS ((const char *)); @@ -473,10 +473,10 @@ extern int re_exec _RE_ARGS ((const char *)); extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); extern int regexec _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, - regmatch_t pmatch[], int eflags)); + regmatch_t pmatch[], int eflags)); extern size_t regerror _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, - size_t errbuf_size)); + size_t errbuf_size)); extern void regfree _RE_ARGS ((regex_t *preg)); #endif /* not __REGEXP_LIBRARY_H__ */ From 185fbb49c9bebc622602bc478d1ff2cb601cfcdd Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:51:19 +0200 Subject: [PATCH 0437/3720] Rename my_mktime() to tm_to_time_t() and make it officially extern. Signed-off-by: Johannes Sixt --- compat/mingw.c | 3 +-- date.c | 13 ++++++++----- git-compat-util.h | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 95ba563a27..488ff404ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -218,7 +218,6 @@ int mkstemp(char *template) int gettimeofday(struct timeval *tv, void *tz) { - extern time_t my_mktime(struct tm *tm); SYSTEMTIME st; struct tm tm; GetSystemTime(&st); @@ -228,7 +227,7 @@ int gettimeofday(struct timeval *tv, void *tz) tm.tm_hour = st.wHour; tm.tm_min = st.wMinute; tm.tm_sec = st.wSecond; - tv->tv_sec = my_mktime(&tm); + tv->tv_sec = tm_to_time_t(&tm); if (tv->tv_sec < 0) return -1; tv->tv_usec = st.wMilliseconds*1000; diff --git a/date.c b/date.c index d6f8bf61c3..35a52576c5 100644 --- a/date.c +++ b/date.c @@ -6,7 +6,10 @@ #include "cache.h" -time_t my_mktime(struct tm *tm) +/* + * This is like mktime, but without normalization of tm_wday and tm_yday. + */ +time_t tm_to_time_t(const struct tm *tm) { static const int mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 @@ -67,7 +70,7 @@ static int local_tzoffset(unsigned long time) t = time; localtime_r(&t, &tm); - t_local = my_mktime(&tm); + t_local = tm_to_time_t(&tm); if (t_local < t) { eastwest = -1; @@ -322,7 +325,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, if (!now_tm) return 1; - specified = my_mktime(r); + specified = tm_to_time_t(r); /* Be it commit time or author time, it does not make * sense to specify timestamp way into the future. Make @@ -572,7 +575,7 @@ int parse_date(const char *date, char *result, int maxlen) } /* mktime uses local timezone */ - then = my_mktime(&tm); + then = tm_to_time_t(&tm); if (offset == -1) offset = (then - mktime(&tm)) / 60; @@ -611,7 +614,7 @@ void datestamp(char *buf, int bufsize) time(&now); - offset = my_mktime(localtime(&now)) - now; + offset = tm_to_time_t(localtime(&now)) - now; offset /= 60; date_string(now, offset, buf, bufsize); diff --git a/git-compat-util.h b/git-compat-util.h index 46fc2d3cfc..2699db5a99 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -143,6 +143,7 @@ extern void set_error_routine(void (*routine)(const char *err, va_list params)); extern void set_warn_routine(void (*routine)(const char *warn, va_list params)); extern int prefixcmp(const char *str, const char *prefix); +extern time_t tm_to_time_t(const struct tm *tm); #ifdef NO_MMAP From 3c965bf3715bce76e69ad8fecee99dca4678d676 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:53:04 +0200 Subject: [PATCH 0438/3720] Handle getenv("TMPDIR") in a getenv() wrapper. This removes an #ifdef MINGW in path.c. Signed-off-by: Johannes Sixt --- compat/mingw.c | 13 +++++++++++++ compat/mingw.h | 3 +++ path.c | 7 ------- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 488ff404ce..116b4ca970 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -366,6 +366,19 @@ char *mingw_getcwd(char *pointer, int len) return ret; } +#undef getenv +char *mingw_getenv(const char *name) +{ + char *result = getenv(name); + if (!result && !strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } + return result; +} + /* * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx * (Parsing C++ Command-Line Arguments) diff --git a/compat/mingw.h b/compat/mingw.h index 6965e3f2df..6bc049ad99 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -145,6 +145,9 @@ int mingw_open (const char *filename, int oflags, ...); char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd +char *mingw_getenv(const char *name); +#define getenv mingw_getenv + struct hostent *mingw_gethostbyname(const char *host); #define gethostbyname mingw_gethostbyname diff --git a/path.c b/path.c index 5da41c709d..7a35a26a16 100644 --- a/path.c +++ b/path.c @@ -75,13 +75,6 @@ int git_mkstemp(char *path, size_t len, const char *template) size_t n; tmp = getenv("TMPDIR"); -#ifdef __MINGW32__ - /* on Windows it is TMP and TEMP */ - if (!tmp) - tmp = getenv("TMP"); - if (!tmp) - tmp = getenv("TEMP"); -#endif if (!tmp) tmp = "/tmp"; n = snprintf(path, len, "%s/%s", tmp, template); From cc81aaa17e0594f7ed9a84557d013f594c9c1ce1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:56:06 +0200 Subject: [PATCH 0439/3720] Remove #ifdef STRIP_EXTENSION from git.c Instead, we use a condition that is known at compile-time to have the compiler optimize away the code if it is not needed. Signed-off-by: Johannes Sixt --- git-compat-util.h | 4 ++++ git.c | 15 ++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 2699db5a99..51823ae7af 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -114,6 +114,10 @@ #define PATH_SEP ':' #endif +#ifndef STRIP_EXTENSION +#define STRIP_EXTENSION "" +#endif + #ifndef has_dos_drive_prefix #define has_dos_drive_prefix(path) 0 #endif diff --git a/git.c b/git.c index a4b0a5e807..39db13a202 100644 --- a/git.c +++ b/git.c @@ -369,15 +369,16 @@ static void handle_internal_command(int argc, const char **argv) { "pack-refs", cmd_pack_refs, RUN_SETUP }, }; int i; + static const char ext[] = STRIP_EXTENSION; -#ifdef STRIP_EXTENSION - i = strlen(argv[0]) - strlen(STRIP_EXTENSION); - if (i > 0 && !strcmp(argv[0] + i, STRIP_EXTENSION)) { - char *argv0 = strdup(argv[0]); - argv[0] = cmd = argv0; - argv0[i] = '\0'; + if (sizeof(ext) > 1) { + i = strlen(argv[0]) - strlen(ext); + if (i > 0 && !strcmp(argv[0] + i, ext)) { + char *argv0 = strdup(argv[0]); + argv[0] = cmd = argv0; + argv0[i] = '\0'; + } } -#endif /* Turn "git cmd --help" into "git help cmd" */ if (argc > 1 && !strcmp(argv[1], "--help")) { From ab87ad4c62eaa6d415346676ad7d5457d739ebd3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:56:39 +0200 Subject: [PATCH 0440/3720] Touch-ups in comments and error strings in compat/mingw.c Signed-off-by: Johannes Sixt --- compat/mingw.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 116b4ca970..3a05fe7da6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -189,7 +189,7 @@ int mingw_utime (const char *file_name, const struct utimbuf *times) /* must have write permission */ if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) - return -1; + return -1; time_t_to_filetime(times->modtime, &mft); time_t_to_filetime(times->actime, &aft); @@ -907,13 +907,12 @@ static int one_shot; static sig_handler_t timer_fn = SIG_DFL; /* The timer works like this: - * The thread, ticktack(), is basically a trivial routine that most of the - * time only waits to receive the signal to terminate. The main thread - * tells the thread to terminate by setting the timer_event to the signalled + * The thread, ticktack(), is a trivial routine that most of the time + * only waits to receive the signal to terminate. The main thread tells + * the thread to terminate by setting the timer_event to the signalled * state. - * But ticktack() does not wait indefinitely; instead, it interrupts the - * wait state every now and then, namely exactly after timer's interval - * length. At these opportunities it calls the signal handler. + * But ticktack() interrupts the wait state after the timer's interval + * length to call the signal handler. */ static __stdcall unsigned ticktack(void *dummy) @@ -939,7 +938,7 @@ static int start_timer_thread(void) error("cannot start timer thread"); } else return errno = ENOMEM, - error("cannot allocate resources timer"); + error("cannot allocate resources for timer"); return 0; } @@ -974,11 +973,11 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out) if (out != NULL) return errno = EINVAL, - error("setitmer param 3 != NULL not implemented"); + error("setitimer param 3 != NULL not implemented"); if (!is_timeval_eq(&in->it_interval, &zero) && !is_timeval_eq(&in->it_interval, &in->it_value)) return errno = EINVAL, - error("setitmer: it_interval must be zero or eq it_value"); + error("setitimer: it_interval must be zero or eq it_value"); if (timer_thread) stop_timer_thread(); From b0115de33336cda96cb3c0637a7985c7c5b436ac Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:57:56 +0200 Subject: [PATCH 0441/3720] Remove a 'break' that was accidentally left over The conversion of the 'switch' statement to an 'if' cascade forgot to remove the break. Signed-off-by: Johannes Sixt --- setup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.c b/setup.c index ec33147ad8..8bb7b10174 100644 --- a/setup.c +++ b/setup.c @@ -35,7 +35,6 @@ static int sanitary_path_copy(char *dst, const char *src) if (!src[1]) { /* (1) */ src++; - break; } else if (is_dir_sep(src[1])) { /* (2) */ src += 2; From 16502c915ff3bc148c53eaae773eb0dbe895caa9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:59:12 +0200 Subject: [PATCH 0442/3720] Hand-roll the search for the program name to remove #ifdef MINGW. We now use is_dir_sep() to scan argv[0] for the program name. Signed-off-by: Johannes Sixt --- git.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/git.c b/git.c index 39db13a202..871b93ca7e 100644 --- a/git.c +++ b/git.c @@ -396,8 +396,8 @@ static void handle_internal_command(int argc, const char **argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] ? argv[0] : "git-help"; - char *slash = strrchr(cmd, '/'); + const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; + char *slash = (char *)cmd + strlen(cmd); const char *cmd_path = NULL; int done_alias = 0; @@ -406,12 +406,10 @@ int main(int argc, const char **argv) * name, and the dirname as the default exec_path * if we don't have anything better. */ -#ifdef __MINGW32__ - char *bslash = strrchr(cmd, '\\'); - if (!slash || (bslash && bslash > slash)) - slash = bslash; -#endif - if (slash) { + do + --slash; + while (cmd <= slash && !is_dir_sep(*slash)); + if (cmd <= slash) { *slash++ = 0; cmd_path = cmd; cmd = slash; From dcaceb0a278ca1293cb0b50cc60cdde721dc0de0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Jul 2008 09:03:53 +0200 Subject: [PATCH 0443/3720] Revert "Change the name of hook scripts to make them not executable by default." This reverts commits 13cae476, bdb6d4ec, daabe66f. They are not necessary anymore, because the sample hooks now have a .sample postfix. --- Makefile | 3 +-- templates/Makefile | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Makefile b/Makefile index bc7256d170..78e08d3745 100644 --- a/Makefile +++ b/Makefile @@ -743,7 +743,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe - NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig endif @@ -1058,7 +1057,7 @@ ifndef NO_TCLTK $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all endif $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all - $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) NOEXECTEMPL='$(NOEXECTEMPL)' + $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) strip: $(PROGRAMS) git$X $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X diff --git a/templates/Makefile b/templates/Makefile index ab2c823ae0..9f3f1fc352 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -10,8 +10,6 @@ RM ?= rm -f prefix ?= $(HOME) template_instdir ?= $(prefix)/share/git-core/templates # DESTDIR= -# set NOEXECTEMPL to non-empty to change the names of hook scripts -# so that the tools will not find them # Shell quote (do not use $(call) to accommodate ancient setups); DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) @@ -34,7 +32,6 @@ boilerplates.made : $(bpsrc) $(INSTALL) -d -m 755 blt/$$dir && \ case "$$boilerplate" in \ *--) ;; \ - hooks--*) cp -p $$boilerplate blt/$${dst}$(NOEXECTEMPL) ;; \ *) cp -p $$boilerplate blt/$$dst ;; \ esac || exit; \ done && \ From a3fb126011ff47be25b194f80b74e851ef3c7482 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Jul 2008 09:29:45 +0200 Subject: [PATCH 0444/3720] t4127-apply-same-fn: Avoid sed -i Signed-off-by: Johannes Sixt --- t/t4127-apply-same-fn.sh | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/t/t4127-apply-same-fn.sh b/t/t4127-apply-same-fn.sh index 2a6ed77c65..1f859dd908 100755 --- a/t/t4127-apply-same-fn.sh +++ b/t/t4127-apply-same-fn.sh @@ -4,6 +4,11 @@ test_description='apply same filename' . ./test-lib.sh +modify () { + sed -e "$1" < "$2" > "$2".x && + mv "$2".x "$2" +} + test_expect_success setup ' for i in a b c d e f g h i j k l m do @@ -14,10 +19,10 @@ test_expect_success setup ' git commit -m initial ' test_expect_success 'apply same filename with independent changes' ' - sed -i -e "s/^d/z/" same_fn && + modify "s/^d/z/" same_fn && git diff > patch0 && git add same_fn && - sed -i -e "s/^i/y/" same_fn && + modify "s/^i/y/" same_fn && git diff >> patch0 && cp same_fn same_fn2 && git reset --hard && @@ -27,10 +32,10 @@ test_expect_success 'apply same filename with independent changes' ' test_expect_success 'apply same filename with overlapping changes' ' git reset --hard - sed -i -e "s/^d/z/" same_fn && + modify "s/^d/z/" same_fn && git diff > patch0 && git add same_fn && - sed -i -e "s/^e/y/" same_fn && + modify "s/^e/y/" same_fn && git diff >> patch0 && cp same_fn same_fn2 && git reset --hard && @@ -41,10 +46,10 @@ test_expect_success 'apply same filename with overlapping changes' ' test_expect_success 'apply same new filename after rename' ' git reset --hard git mv same_fn new_fn - sed -i -e "s/^d/z/" new_fn && + modify "s/^d/z/" new_fn && git add new_fn && git diff -M --cached > patch1 && - sed -i -e "s/^e/y/" new_fn && + modify "s/^e/y/" new_fn && git diff >> patch1 && cp new_fn new_fn2 && git reset --hard && @@ -55,11 +60,11 @@ test_expect_success 'apply same new filename after rename' ' test_expect_success 'apply same old filename after rename -- should fail.' ' git reset --hard git mv same_fn new_fn - sed -i -e "s/^d/z/" new_fn && + modify "s/^d/z/" new_fn && git add new_fn && git diff -M --cached > patch1 && git mv new_fn same_fn - sed -i -e "s/^e/y/" same_fn && + modify "s/^e/y/" same_fn && git diff >> patch1 && git reset --hard && test_must_fail git apply patch1 @@ -68,15 +73,15 @@ test_expect_success 'apply same old filename after rename -- should fail.' ' test_expect_success 'apply A->B (rename), C->A (rename), A->A -- should pass.' ' git reset --hard git mv same_fn new_fn - sed -i -e "s/^d/z/" new_fn && + modify "s/^d/z/" new_fn && git add new_fn && git diff -M --cached > patch1 && git commit -m "a rename" && git mv other_fn same_fn - sed -i -e "s/^e/y/" same_fn && + modify "s/^e/y/" same_fn && git add same_fn && git diff -M --cached >> patch1 && - sed -i -e "s/^g/x/" same_fn && + modify "s/^g/x/" same_fn && git diff >> patch1 && git reset --hard HEAD^ && git apply patch1 From 56cfc88a46842653218c1575d63068a0b1b8bb66 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Jul 2008 11:07:38 +0200 Subject: [PATCH 0445/3720] Avoid /dev/zero in tests. On Windows, we do not have /dev/zero or an equivalent. Work around this using a shell loop that produces zero bytes. Signed-off-by: Johannes Sixt --- t/t5302-pack-index.sh | 8 +++++++- t/t5303-pack-corruption-resilience.sh | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index ecec591634..74e10aaf09 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -6,6 +6,12 @@ test_description='pack index with 64-bit offsets and object CRC' . ./test-lib.sh +zeros () { + while :; do + echo -n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + done | tr x '\0' +} + test_expect_success \ 'setup' \ 'rm -rf .git @@ -168,7 +174,7 @@ test_expect_success \ git-index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && git verify-pack ".git/objects/pack/pack-${pack1}.pack" && chmod +w ".git/objects/pack/pack-${pack1}.idx" && - dd if=/dev/zero of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ + zeros | dd of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ bs=1 count=4 seek=$((8 + 256 * 4 + `wc -l /dev/null || exit 1 diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 31b20b21d2..874c6fe705 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -41,11 +41,17 @@ create_new_pack() { git verify-pack -v ${pack}.pack } +zeros () { + while :; do + echo -n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + done | tr x '\0' +} + do_corrupt_object() { ofs=`git show-index < ${pack}.idx | grep $1 | cut -f1 -d" "` && ofs=$(($ofs + $2)) && chmod +w ${pack}.pack && - dd if=/dev/zero of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs && + zeros | dd of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs && test_must_fail git verify-pack ${pack}.pack } From 17e3d3f605ce39dd85dcded65cd6ba08ccf7ee73 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 2 Jul 2008 16:18:12 +0200 Subject: [PATCH 0446/3720] Revert "fast-import: fix compilation on MinGW" This reverts commit 54d99a7724a0c7fb53bcdc7d850034e9890a0138. A dummy implementation of getppid was added to the compat layer, so this ifdef is no longer needed. --- fast-import.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fast-import.c b/fast-import.c index 271b93cf76..e72b286794 100644 --- a/fast-import.c +++ b/fast-import.c @@ -391,9 +391,7 @@ static void write_crash_report(const char *err) fprintf(rpt, "fast-import crash report:\n"); fprintf(rpt, " fast-import process: %d\n", getpid()); -#ifndef __MINGW32__ fprintf(rpt, " parent process : %d\n", getppid()); -#endif fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL)); fputc('\n', rpt); From 5278ad45e345e4e7f0418b4733f54823b7199801 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 2 Jul 2008 16:27:40 +0200 Subject: [PATCH 0447/3720] Revert "Avoid calling signal(SIGPIPE, ..) for MinGW builds." This reverts commit 56be985fe902a4af8c7f0bbe4541ef783ead827f. SIGPIPE is defined in the compat layer, so this ifdef is no longer needed. --- builtin-verify-tag.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index 540e3b9b75..92eaa89a45 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -100,11 +100,9 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) i++; } -#ifndef __MINGW32__ /* sometimes the program was terminated because this signal * was received in the process of writing the gpg input: */ signal(SIGPIPE, SIG_IGN); -#endif while (i < argc) if (verify_tag(argv[i++], verbose)) had_error = 1; From c00ce6091514f55931cb15d8dec014767ad918b4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 2 Jul 2008 16:32:48 +0200 Subject: [PATCH 0448/3720] convert.c: Fix style (no functional changes) --- convert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/convert.c b/convert.c index f24ac25c49..1d3e8b02f1 100644 --- a/convert.c +++ b/convert.c @@ -63,7 +63,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat * } // If file ends with EOF then don't count this EOF as non-printable - if ( size >= 1 && buf[size-1] == '\032' ) + if (size >= 1 && buf[size-1] == '\032') stats->nonprintable--; } From adf63bc4e33d9fc5b2e7079aec484d6563788db3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 2 Jul 2008 19:11:11 +0200 Subject: [PATCH 0449/3720] Revert "verify_path(): do not allow absolute paths" This reverts commit 8e78bd571071805ca9f34a6bc93846f6e5b15f4e. We do support absolute paths on Windows now. --- read-cache.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/read-cache.c b/read-cache.c index 5b109606e0..8e5fbb6192 100644 --- a/read-cache.c +++ b/read-cache.c @@ -634,11 +634,6 @@ int verify_path(const char *path) { char c; -#ifdef __MINGW32__ - if (is_absolute_path(path)) - return error("Cannot handle absolute path: %s", path); -#endif - goto inside; for (;;) { if (!c) From 861bebb42573c2812db44ff5a5dcfa4b7cd28224 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 3 Jul 2008 07:56:21 +0200 Subject: [PATCH 0450/3720] Revert "Fake reencoding success under NO_ICONV instead of returning NULL." We have a working iconv now, so this workaround is no longer needed. --- utf8.c | 7 ------- utf8.h | 4 ++++ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/utf8.c b/utf8.c index b07d43e580..dc3735364f 100644 --- a/utf8.c +++ b/utf8.c @@ -388,11 +388,4 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e iconv_close(conv); return out; } -#else -char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding) -{ - if (!in_encoding) - return NULL; - return xstrdup(in); -} #endif diff --git a/utf8.h b/utf8.h index f22ef3133c..98cce1b038 100644 --- a/utf8.h +++ b/utf8.h @@ -10,6 +10,10 @@ int is_encoding_utf8(const char *name); int print_wrapped_text(const char *text, int indent, int indent2, int len); +#ifndef NO_ICONV char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding); +#else +#define reencode_string(a,b,c) NULL +#endif #endif From 065eb05f3fca2b9a2a7a1fb39ca7dffd7f932f45 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 3 Jul 2008 08:18:47 +0200 Subject: [PATCH 0451/3720] connect.c: Remove comment that will not be sent upstream --- connect.c | 1 - 1 file changed, 1 deletion(-) diff --git a/connect.c b/connect.c index 11fa151eb3..0d007f366f 100644 --- a/connect.c +++ b/connect.c @@ -596,7 +596,6 @@ struct child_process *git_connect(int fd[2], const char *url_orig, die("command line too long"); conn->in = conn->out = -1; - /* be sure to increase this size if you add more args */ conn->argv = arg = xcalloc(6, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); From 3f3d496f8b8bf0bb2e74b0bf8268d3a19cbf553d Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 3 Jul 2008 08:21:43 +0200 Subject: [PATCH 0452/3720] help.c: Fix line endings (CRLF -> LF) --- help.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/help.c b/help.c index 2ed68389fe..fc45f463e3 100644 --- a/help.c +++ b/help.c @@ -28,12 +28,12 @@ enum help_format { HELP_FORMAT_WEB, }; -static int show_all = 0; -#ifdef __MINGW32__ -static enum help_format help_format = HELP_FORMAT_WEB; +static int show_all = 0; +#ifdef __MINGW32__ +static enum help_format help_format = HELP_FORMAT_WEB; #else static enum help_format help_format = HELP_FORMAT_MAN; -#endif +#endif static struct option builtin_help_options[] = { OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), From 2d556c22398cc4b76edce448a8f24239eb0e8631 Mon Sep 17 00:00:00 2001 From: Eric Raible Date: Thu, 26 Jun 2008 22:04:47 +0000 Subject: [PATCH 0453/3720] Teach lookup_prog not to select directories Without this simple fix "git gui" in the git source directory finds the git-gui directory instead of the tcl script in /usr/bin. Signed-off-by: Eric Raible Signed-off-by: Johannes Sixt --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3a05fe7da6..bb33c8dfa2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -536,7 +536,8 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on return xstrdup(path); path[strlen(path)-4] = '\0'; if ((!exe_only || isexe) && access(path, F_OK) == 0) - return xstrdup(path); + if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY)) + return xstrdup(path); return NULL; } From 2a337eda67f4e62520fb38a48c51577f572065da Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 7 Jul 2008 11:10:20 +0200 Subject: [PATCH 0454/3720] builtin-clone: Use is_dir_sep() instead of '/' Signed-off-by: Johannes Sixt --- builtin-clone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-clone.c b/builtin-clone.c index 643c7d4169..fddf47fabf 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -115,7 +115,7 @@ static char *guess_dir_name(const char *repo, int is_bundle) if (!after_slash_or_colon) end = p; p += 7; - } else if (*p == '/' || *p == ':') { + } else if (is_dir_sep(*p) || *p == ':') { if (end == limit) end = p; after_slash_or_colon = 1; From 14c8eef4e02f9c2f7955c435467f42fa3aeac072 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Wed, 9 Jul 2008 17:34:20 -0400 Subject: [PATCH 0455/3720] Add ANSI control code emulation for the Windows console This adds only the minimum necessary to keep git pull/merge's diffstat from wrapping. Notably absent is support for the K (erase) operation, and support for POSIX write. Signed-off-by: Peter Harris Signed-off-by: Johannes Sixt --- Makefile | 2 +- compat/mingw.h | 11 ++ compat/winansi.c | 345 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 compat/winansi.c diff --git a/Makefile b/Makefile index 78e08d3745..2c6cc9d196 100644 --- a/Makefile +++ b/Makefile @@ -740,7 +740,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe template_dir = ../share/git-core/templates/ diff --git a/compat/mingw.h b/compat/mingw.h index 6bc049ad99..5f11114890 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -193,6 +193,17 @@ static inline unsigned int git_ntohl(unsigned int x) sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +/* + * ANSI emulation wrappers + */ + +int winansi_fputs(const char *str, FILE *stream); +int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); +int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +#define fputs winansi_fputs +#define printf(...) winansi_printf(__VA_ARGS__) +#define fprintf(...) winansi_fprintf(__VA_ARGS__) + /* * git specific compatibility */ diff --git a/compat/winansi.c b/compat/winansi.c new file mode 100644 index 0000000000..e2d96dfe6f --- /dev/null +++ b/compat/winansi.c @@ -0,0 +1,345 @@ +/* + * Copyright 2008 Peter Harris + */ + +#include +#include "../git-compat-util.h" + +/* + Functions to be wrapped: +*/ +#undef printf +#undef fprintf +#undef fputs +/* TODO: write */ + +/* + ANSI codes used by git: m, K + + This file is git-specific. Therefore, this file does not attempt + to implement any codes that are not used by git. + + TODO: K +*/ + +static HANDLE console; +static WORD plain_attr; +static WORD attr; +static int negative; + +static void init(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + static int initialized = 0; + if (initialized) + return; + + console = GetStdHandle(STD_OUTPUT_HANDLE); + if (console == INVALID_HANDLE_VALUE) + console = NULL; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + attr = plain_attr = sbi.wAttributes; + negative = 0; + + initialized = 1; +} + + +#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) + +static void set_console_attr(void) +{ + WORD attributes = attr; + if (negative) { + attributes &= ~FOREGROUND_ALL; + attributes &= ~BACKGROUND_ALL; + + /* This could probably use a bitmask + instead of a series of ifs */ + if (attr & FOREGROUND_RED) + attributes |= BACKGROUND_RED; + if (attr & FOREGROUND_GREEN) + attributes |= BACKGROUND_GREEN; + if (attr & FOREGROUND_BLUE) + attributes |= BACKGROUND_BLUE; + + if (attr & BACKGROUND_RED) + attributes |= FOREGROUND_RED; + if (attr & BACKGROUND_GREEN) + attributes |= FOREGROUND_GREEN; + if (attr & BACKGROUND_BLUE) + attributes |= FOREGROUND_BLUE; + } + SetConsoleTextAttribute(console, attributes); +} + +static const char *set_attr(const char *str) +{ + const char *func; + size_t len = strspn(str, "0123456789;"); + func = str + len; + + switch (*func) { + case 'm': + do { + long val = strtol(str, (char **)&str, 10); + switch (val) { + case 0: /* reset */ + attr = plain_attr; + negative = 0; + break; + case 1: /* bold */ + attr |= FOREGROUND_INTENSITY; + break; + case 2: /* faint */ + case 22: /* normal */ + attr &= ~FOREGROUND_INTENSITY; + break; + case 3: /* italic */ + /* Unsupported */ + break; + case 4: /* underline */ + case 21: /* double underline */ + /* Wikipedia says this flag does nothing */ + /* Furthermore, mingw doesn't define this flag + attr |= COMMON_LVB_UNDERSCORE; */ + break; + case 24: /* no underline */ + /* attr &= ~COMMON_LVB_UNDERSCORE; */ + break; + case 5: /* slow blink */ + case 6: /* fast blink */ + /* We don't have blink, but we do have + background intensity */ + attr |= BACKGROUND_INTENSITY; + break; + case 25: /* no blink */ + attr &= ~BACKGROUND_INTENSITY; + break; + case 7: /* negative */ + negative = 1; + break; + case 27: /* positive */ + negative = 0; + break; + case 8: /* conceal */ + case 28: /* reveal */ + /* Unsupported */ + break; + case 30: /* Black */ + attr &= ~FOREGROUND_ALL; + break; + case 31: /* Red */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED; + break; + case 32: /* Green */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN; + break; + case 33: /* Yellow */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + case 34: /* Blue */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_BLUE; + break; + case 35: /* Magenta */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + case 36: /* Cyan */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case 37: /* White */ + attr |= FOREGROUND_RED | + FOREGROUND_GREEN | + FOREGROUND_BLUE; + break; + case 38: /* Unknown */ + break; + case 39: /* reset */ + attr &= ~FOREGROUND_ALL; + attr |= (plain_attr & FOREGROUND_ALL); + break; + case 40: /* Black */ + attr &= ~BACKGROUND_ALL; + break; + case 41: /* Red */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED; + break; + case 42: /* Green */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN; + break; + case 43: /* Yellow */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + case 44: /* Blue */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_BLUE; + break; + case 45: /* Magenta */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + case 46: /* Cyan */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case 47: /* White */ + attr |= BACKGROUND_RED | + BACKGROUND_GREEN | + BACKGROUND_BLUE; + break; + case 48: /* Unknown */ + break; + case 49: /* reset */ + attr &= ~BACKGROUND_ALL; + attr |= (plain_attr & BACKGROUND_ALL); + break; + default: + /* Unsupported code */ + break; + } + str++; + } while (*(str-1) == ';'); + + set_console_attr(); + break; + case 'K': + /* TODO */ + break; + default: + /* Unsupported code */ + break; + } + + return func + 1; +} + +static int ansi_emulate(const char *str, FILE *stream) +{ + int rv = 0; + const char *pos = str; + + while (*pos) { + pos = strstr(str, "\033["); + if (pos) { + size_t len = pos - str; + + if (len) { + size_t out_len = fwrite(str, 1, len, stream); + rv += out_len; + if (out_len < len) + return rv; + } + + str = pos + 2; + rv += 2; + + fflush(stream); + + pos = set_attr(str); + rv += pos - str; + str = pos; + } else { + rv += strlen(str); + fputs(str, stream); + return rv; + } + } + return rv; +} + +int winansi_fputs(const char *str, FILE *stream) +{ + int rv; + + if (!isatty(fileno(stream))) + return fputs(str, stream); + + init(); + + if (!console) + return fputs(str, stream); + + rv = ansi_emulate(str, stream); + + if (rv >= 0) + return 0; + else + return EOF; +} + +static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +{ + int len, rv; + char small_buf[256]; + char *buf = small_buf; + va_list cp; + + if (!isatty(fileno(stream))) + goto abort; + + init(); + + if (!console) + goto abort; + + va_copy(cp, list); + len = vsnprintf(small_buf, sizeof(small_buf), format, cp); + va_end(cp); + + if (len > sizeof(small_buf) - 1) { + buf = malloc(len + 1); + if (!buf) + goto abort; + + len = vsnprintf(buf, len + 1, format, list); + } + + rv = ansi_emulate(buf, stream); + + if (buf != small_buf) + free(buf); + return rv; + +abort: + rv = vfprintf(stream, format, list); + return rv; +} + +int winansi_fprintf(FILE *stream, const char *format, ...) +{ + va_list list; + int rv; + + va_start(list, format); + rv = winansi_vfprintf(stream, format, list); + va_end(list); + + return rv; +} + +int winansi_printf(const char *format, ...) +{ + va_list list; + int rv; + + va_start(list, format); + rv = winansi_vfprintf(stdout, format, list); + va_end(list); + + return rv; +} From a31c17daf43e67020d3a1d7a39d1e251709e0633 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 14 Jul 2008 07:16:21 +0200 Subject: [PATCH 0456/3720] help.c (Windows): Revert help.c in preparation for merge of better solution --- help.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/help.c b/help.c index 811f8dbb11..ca9632b6c5 100644 --- a/help.c +++ b/help.c @@ -9,7 +9,6 @@ #include "common-cmds.h" #include "parse-options.h" #include "run-command.h" -#include "dir.h" static struct man_viewer_list { struct man_viewer_list *next; @@ -29,11 +28,7 @@ enum help_format { }; static int show_all = 0; -#ifdef __MINGW32__ -static enum help_format help_format = HELP_FORMAT_WEB; -#else static enum help_format help_format = HELP_FORMAT_MAN; -#endif static struct option builtin_help_options[] = { OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), @@ -649,35 +644,12 @@ static void get_html_page_path(struct strbuf *page_path, const char *page) static void show_html_page(const char *git_cmd) { -#ifdef __MINGW32__ - const char* exec_path = git_exec_path(); - char *htmlpath = make_native_separator( - mkpath("%s/../doc/git/html/%s.html" - , exec_path - , git_cmd) - ); - if (!file_exists(htmlpath)) { - htmlpath = make_native_separator( - mkpath("%s/../doc/git/html/git-%s.html" - , exec_path - , git_cmd) - ); - if (!file_exists(htmlpath)) { - fprintf(stderr, "Can't find HTML help for '%s'.\n" - , git_cmd); - exit(1); - } - } - printf("Launching default browser to display HTML help ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); -#else const char *page = cmd_to_page(git_cmd); struct strbuf page_path; /* it leaks but we exec bellow */ get_html_page_path(&page_path, page); execl_git_cmd("web--browse", "-c", "help.browser", page_path.buf, NULL); -#endif } void help_unknown_cmd(const char *cmd) From 04bad247702047dcf53c87247d72c07513cb90a6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 14 Jul 2008 07:23:02 +0200 Subject: [PATCH 0457/3720] help (Windows): Use msysgit-specific relative path to htmldir --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 06df0ba5be..5b5f1603f1 100644 --- a/Makefile +++ b/Makefile @@ -747,6 +747,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig + htmldir=../doc/git/html/ endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From 9b096dc9bb239309ba87456b7e2af56f436f91a3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 14 Jul 2008 07:28:49 +0200 Subject: [PATCH 0458/3720] help (Windows): Revert leftovers of old implementation --- cache.h | 2 -- path.c | 13 ------------- 2 files changed, 15 deletions(-) diff --git a/cache.h b/cache.h index 2c4d9b3776..0d8eddac77 100644 --- a/cache.h +++ b/cache.h @@ -527,8 +527,6 @@ static inline int is_absolute_path(const char *path) const char *make_absolute_path(const char *path); const char *make_nonrelative_path(const char *path); const char *make_relative_path(const char *abs, const char *base); -/* Convert slashes in place. On Windows to backslashes. */ -char *make_native_separator(char *path); int normalize_absolute_path(char *buf, const char *path); int longest_ancestor_length(const char *path, const char *prefix_list); diff --git a/path.c b/path.c index 96503d96cd..504eae061f 100644 --- a/path.c +++ b/path.c @@ -439,16 +439,3 @@ int longest_ancestor_length(const char *path, const char *prefix_list) return max_len; } - -char *make_native_separator(char* path) { -#ifdef __MINGW32__ - char* c; - for (c = path; *c; c++) { - if (*c == '/') - *c = '\\'; - } - return path; -#else - return path; -#endif -} From 5d54e5d4f2c0ccd3670fc12eaa86047fd0822cf4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 14 Jul 2008 08:00:16 +0200 Subject: [PATCH 0459/3720] setup (Windows): Revert leftovers of old implementation The handling of paths was resolved differently in the MinGW port that is merged to official git. This commit takes this implementation. Signed-off-by: Steffen Prohaska --- setup.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/setup.c b/setup.c index 1fd30c4b43..6cf909463d 100644 --- a/setup.c +++ b/setup.c @@ -381,7 +381,6 @@ const char *setup_git_directory_gently(int *nongit_ok) const char *gitdirenv; const char *gitfile_dir; int len, offset, ceil_offset; - int minoffset = 0; /* * Let's assume that we are in a git repository. @@ -432,8 +431,6 @@ const char *setup_git_directory_gently(int *nongit_ok) if (!getcwd(cwd, sizeof(cwd)-1)) die("Unable to read current working directory"); - if (has_dos_drive_prefix(cwd)) - minoffset = 2; ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs); if (ceil_offset < 0 && has_dos_drive_prefix(cwd)) @@ -464,11 +461,11 @@ const char *setup_git_directory_gently(int *nongit_ok) inside_git_dir = 1; if (!work_tree_env) inside_work_tree = 0; - set_git_dir("."); + setenv(GIT_DIR_ENVIRONMENT, ".", 1); check_repository_format_gently(nongit_ok); return NULL; } - while (offset > minoffset && --offset > ceil_offset && cwd[offset] != '/'); + while (--offset > ceil_offset && cwd[offset] != '/'); if (offset <= ceil_offset) { if (nongit_ok) { if (chdir(cwd)) From e0e7163c215a6e74940cc1b66c7f4461359a7dc1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 15 Jul 2008 10:02:57 +0200 Subject: [PATCH 0460/3720] Windows: set gitexecdir = $(bindir) The "dash-less" change aims to remove git commands from $PATH. It does so by defining a GIT_EXEC_PATH that is different from $(bindir). On Windows we want a relocatable installation of the git tool, so we cannot use an absolute GIT_EXEC_PATH. Therefore, the implementation of builtin_exec_path() on Windows derives the exec-path from the command invocation, and disregards GIT_EXEC_PATH. But this broke when $(gitexecdir) became different from $(bindir), so we restore the earlier behavior here. This counteracts the aims of the "dash-less" change on Windows, but better this way than having no working git at all. Signed-off-by: Johannes Sixt --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 36339d3aff..7d466b3c3b 100644 --- a/Makefile +++ b/Makefile @@ -742,6 +742,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe + gitexecdir = $(bindir) template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig endif From a79b6908829b5804dbfab78050fa9991f59597f9 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 22 Jul 2008 22:07:23 +0200 Subject: [PATCH 0461/3720] Makefile: cleanup leftovers from old winansi implementation --- Makefile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Makefile b/Makefile index f7da7e7870..0cdfcd2762 100644 --- a/Makefile +++ b/Makefile @@ -739,7 +739,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_R_TO_GCC_LINKER = YesPlease INTERNAL_QSORT = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease - WIN_ANSI = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -987,11 +986,6 @@ ifdef NO_EXTERNAL_GREP BASIC_CFLAGS += -DNO_EXTERNAL_GREP endif -ifdef WIN_ANSI - COMPAT_CFLAGS += -DWIN_ANSI - COMPAT_OBJS += compat/winansi.o -endif - ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif From 1ddfb58a5edcbdaf7371fe0036026c57aeed6a2c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 26 Jul 2008 11:27:43 +0200 Subject: [PATCH 0462/3720] Modify mingw_main() workaround to avoid link errors With MinGW's gcc.exe (GCC) 3.4.5 (mingw special) GNU ld version 2.17.50 20060824 the old define caused link errors: git.o: In function `main': C:/msysgit/git/git.c:500: undefined reference to `mingw_main' collect2: ld returned 1 exit status The modified define works. Signed-off-by: Steffen Prohaska --- compat/mingw.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 290a9e6f82..a52e657c51 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -228,9 +228,10 @@ char **env_setenv(char **env, const char *name); * A replacement of main() that ensures that argv[0] has a path */ -#define main(c,v) main(int argc, const char **argv) \ +#define main(c,v) dummy_decl_mingw_main(); \ +static int mingw_main(); \ +int main(int argc, const char **argv) \ { \ - static int mingw_main(); \ argv[0] = xstrdup(_pgmptr); \ return mingw_main(argc, argv); \ } \ From 6cfef43abe77633e8e42389747d406fae87a91f2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 11:17:26 +0200 Subject: [PATCH 0463/3720] Revert "Windows: set gitexecdir = $(bindir)" This reverts commit e0e7163c215a6e74940cc1b66c7f4461359a7dc1. --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 5e3d48183c..b01cf1c993 100644 --- a/Makefile +++ b/Makefile @@ -745,7 +745,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = $(bindir) template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig endif From 01d9b2d0d678204761b2869b5f9ab28f26674fec Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 26 Jul 2008 23:04:41 +0200 Subject: [PATCH 0464/3720] Fix t5602-clone-remote-exec on MSYS MSYS rewrites /something/bin/... into a Windows path that is somewhere inside the MSYS installation directory. We make the path relative so that this rewriting is not triggered. Signed-off-by: Johannes Sixt --- t/t5602-clone-remote-exec.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh index 8367a6845f..ce64449c0b 100755 --- a/t/t5602-clone-remote-exec.sh +++ b/t/t5602-clone-remote-exec.sh @@ -18,8 +18,8 @@ test_expect_success 'clone calls git-upload-pack unqualified with no -u option' ' test_expect_success 'clone calls specified git-upload-pack with -u option' ' - GIT_SSH=./not_ssh git clone -u /something/bin/git-upload-pack localhost:/path/to/repo junk - echo "localhost /something/bin/git-upload-pack '\''/path/to/repo'\''" >expected + GIT_SSH=./not_ssh git clone -u ./something/bin/git-upload-pack localhost:/path/to/repo junk + echo "localhost ./something/bin/git-upload-pack '\''/path/to/repo'\''" >expected test_cmp expected not_ssh_output ' From 967b742f714410e2cf4d14fb3a0522000ec1d4a7 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 27 Jul 2008 09:53:02 +0200 Subject: [PATCH 0465/3720] Makefile: Fix crlf newline Signed-off-by: Steffen Prohaska --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0797e070f6..b2bc0efe10 100644 --- a/Makefile +++ b/Makefile @@ -755,7 +755,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 - X = .exe + X = .exe NOEXECTEMPL = .noexec gitexecdir = ../libexec/git-core template_dir = ../share/git-core/templates/ From dd487dc5c3daae2466dd7ec539259d96f08917de Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 29 Jul 2008 22:29:15 +0200 Subject: [PATCH 0466/3720] t7001-mv: skip symlink tests Signed-off-by: Johannes Sixt --- t/t7001-mv.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 910a28c7e2..da5d22bd44 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -173,6 +173,7 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' ' rm -f dirty dirty2 +test "$no_symlinks" || test_expect_success 'git mv should overwrite symlink to a file' ' rm -fr .git && @@ -192,6 +193,7 @@ test_expect_success 'git mv should overwrite symlink to a file' ' rm -f moved symlink +test "$no_symlinks" || test_expect_success 'git mv should overwrite file with a symlink' ' rm -fr .git && From 7c2ca986515e2009ab29080e57ae8b38c921ba4d Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:11:28 +0200 Subject: [PATCH 0467/3720] gitk: Fix wrong merge This fixes the wrong conflict resolution of merge 5673e9999d7e120f4b68c2c5a61c5ec48ec38cad --- gitk-git/gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index c6b06df56b..9636d15115 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9993,4 +9993,4 @@ if {[info exists permviews]} { } } focus -force . -getcommits +getcommits {} From a55f5a7b8c73cf4f70110ececcf56e5ebe84702c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 18 Aug 2008 08:59:08 +0200 Subject: [PATCH 0468/3720] MinGW: t3700: skip file-globbing test The test adds a file that has backslashes in the basename. This is not possible on Windows. Signed-off-by: Johannes Sixt --- t/t3700-add.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 22519dd101..93b9ac08ab 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -185,6 +185,7 @@ test_expect_success 'git add --refresh' ' if case $(uname -s) in *MINGW*) :;; *) false;; esac then say "chmod 0 does not make files unreadable - skipping tests" + say "cannot have backslashes in file names - skipping test" else test_expect_success 'git add should fail atomically upon an unreadable file' ' @@ -230,8 +231,6 @@ test_expect_success 'git add (add.ignore-errors = false)' ' ! ( git ls-files foo1 | grep foo1 ) ' -fi # skip chmod 0 tests - test_expect_success 'git add '\''fo\[ou\]bar'\'' ignores foobar' ' git reset --hard && touch fo\[ou\]bar foobar && @@ -240,4 +239,6 @@ test_expect_success 'git add '\''fo\[ou\]bar'\'' ignores foobar' ' ! ( git ls-files foobar | grep foobar ) ' +fi # skip chmod 0 and bslash-in-filename tests + test_done From 43e10bb31a816d8fd435536650cf902ecdc70939 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 28 Aug 2008 12:53:51 +0200 Subject: [PATCH 0469/3720] Skip a test related to symbolic links. --- t/t0055-beyond-symlinks.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh index b29c37a5a4..fabfaf3578 100755 --- a/t/t0055-beyond-symlinks.sh +++ b/t/t0055-beyond-symlinks.sh @@ -4,6 +4,11 @@ test_description='update-index and add refuse to add beyond symlinks' . ./test-lib.sh +if test "$no_symlinks"; then + say "symbolic links not supported - skipping tests" + test_done +fi + test_expect_success setup ' >a && mkdir b && From fa7fbeb525b11c21a5caa2ee4d8a027405f2be6f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:39:25 +0200 Subject: [PATCH 0470/3720] Windows: Add workaround for MSYS' path conversion MSYS' automatic path conversion causes problems when passing paths as defines ('-D' arguments to the compiler). MSYS tries to be smart and converts absolute paths to native Windows paths, e.g. if MSYS sees "/bin" it converts it to "c:/msysgit/bin". But we want completely unmodified paths; e.g. if we set bindir in the Makefile to "/bin", the define BINDIR shall expand to "/bin". Conversion to absolute Windows path will takes place later, during runtime. This commit adds a workaround by replacing "/" with its octal representation "\057", effectively hiding the path from MSYS' path conversion mechanism. MSYS does no longer see the absolute path and therefore leaves it alone. --- Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 8d81095765..f716fda416 100644 --- a/Makefile +++ b/Makefile @@ -1049,6 +1049,12 @@ template_dir_SQ = $(subst ','\'',$(template_dir)) htmldir_SQ = $(subst ','\'',$(htmldir)) prefix_SQ = $(subst ','\'',$(prefix)) +ETC_GITCONFIG_SQ_C = $(subst /,\057,$(ETC_GITCONFIG_SQ)) +bindir_SQ_C = $(subst /,\057,$(bindir_SQ)) +gitexecdir_SQ_C = $(subst /,\057,$(gitexecdir_SQ)) +htmldir_SQ_C = $(subst /,\057,$(htmldir_SQ)) +template_dir_SQ_C = $(subst /,\057,$(template_dir_SQ)) + SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) @@ -1100,7 +1106,7 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS) help.o: help.c common-cmds.h GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ - '-DGIT_HTML_PATH="$(htmldir_SQ)"' \ + '-DGIT_HTML_PATH="$(htmldir_SQ_C)"' \ '-DGIT_MAN_PATH="$(mandir_SQ)"' \ '-DGIT_INFO_PATH="$(infodir_SQ)"' $< @@ -1207,12 +1213,12 @@ git.o git.spec \ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< exec_cmd.o: exec_cmd.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ_C)"' -DBINDIR='"$(bindir_SQ_C)"' $< builtin-init-db.o: builtin-init-db.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ_C)"' $< config.o: config.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ_C)"' $< http.o: http.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $< From 7b6c6496374073d4519a035b5c2053395a60e014 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 10 Aug 2008 17:52:36 +0200 Subject: [PATCH 0471/3720] system_path(): Add prefix computation at runtime if RUNTIME_PREFIX set This commit modifies system_path() to compute the prefix at runtime if configured to do so. If RUNTIME_PREFIX is defined, system_path() tries to strip known directories that executables can be located in from the path of the executable. If the path is successfully stripped it is used as the prefix. For example, if the executable is "/msysgit/bin/git" and BINDIR is "/bin", then the prefix is computed as "/msysgit". We report an error if the runtime prefix computation fails, which can happen if the executable is not installed at a known location. The user should know that the global configuration is not picked up, because this can cause unexpected behavior. If we explicitly want to ignore system wide paths, we can set the environment variable GIT_CONFIG_NOSYSTEM, as our tests do. The implementation requires that argv0_path is set up properly, which is currently the case only on Windows. argv0_path must point to the absolute path of the directory of the executable, which is verified by two calls to assert(). On Windows, the wrapper for main() (see compat/mingw.h) guarantees that this is the case. On Unix, further work is required before RUNTIME_PREFIX can be enabled. --- Makefile | 3 +++ exec_cmd.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f716fda416..b229bff5fb 100644 --- a/Makefile +++ b/Makefile @@ -989,6 +989,9 @@ ifdef INTERNAL_QSORT COMPAT_CFLAGS += -DINTERNAL_QSORT COMPAT_OBJS += compat/qsort.o endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif ifdef THREADED_DELTA_SEARCH BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH diff --git a/exec_cmd.c b/exec_cmd.c index ce6741eb68..9fa89b8502 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,11 +9,48 @@ static const char *argv0_path; const char *system_path(const char *path) { - if (!is_absolute_path(path) && argv0_path) { - struct strbuf d = STRBUF_INIT; - strbuf_addf(&d, "%s/%s", argv0_path, path); - path = strbuf_detach(&d, NULL); +#ifdef RUNTIME_PREFIX + static const char *prefix; + + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix) { + const char *strip[] = { + GIT_EXEC_PATH, + BINDIR, + 0 + }; + const char **s; + + for (s = strip; *s; s++) { + const char *sargv = argv0_path + strlen(argv0_path); + const char *ss = *s + strlen(*s); + while (argv0_path < sargv && *s < ss + && (*sargv == *ss || + (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { + sargv--; + ss--; + } + if (*s == ss) { + struct strbuf d = STRBUF_INIT; + strbuf_add(&d, argv0_path, sargv - argv0_path); + prefix = strbuf_detach(&d, NULL); + break; + } + } } + + if (!prefix) { + fprintf(stderr, "RUNTIME_PREFIX requested for path '%s', " + "but prefix computation failed.\n", path); + return path; + } + + struct strbuf d = STRBUF_INIT; + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); +#endif return path; } From f2fdec9debe6803204ce9dd734058188110e3cf9 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 0472/3720] Refactor git_set_argv0_path() to git_extract_argv0_path() This commit moves the code that computes the dirname of argv[0] from git.c's main() to git_set_argv0_path() and renames the function to git_extract_argv0_path(). This makes the code in git.c's main less cluttered, and we can use the direname computation from other main() functions too. [spr: split Steve's original commit and wrote new commit message. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- exec_cmd.c | 15 +++++++++++++-- exec_cmd.h | 2 +- git.c | 20 +++++--------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 9fa89b8502..46ebf7ec82 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -54,9 +54,20 @@ const char *system_path(const char *path) return path; } -void git_set_argv0_path(const char *path) +const char *git_extract_argv0_path(const char *argv0) { - argv0_path = path; + const char *slash = argv0 + strlen(argv0); + + do + --slash; + while (slash >= argv0 && !is_dir_sep(*slash)); + + if (slash >= argv0) { + argv0_path = xstrndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; } void git_set_argv_exec_path(const char *exec_path) diff --git a/exec_cmd.h b/exec_cmd.h index 594f961387..392e9032c3 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -2,7 +2,7 @@ #define GIT_EXEC_CMD_H extern void git_set_argv_exec_path(const char *exec_path); -extern void git_set_argv0_path(const char *path); +extern const char* git_extract_argv0_path(const char *path); extern const char* git_exec_path(void); extern void setup_path(void); extern const char **prepare_git_cmd(const char **argv); diff --git a/git.c b/git.c index fdb0f71019..cfcedc20dc 100644 --- a/git.c +++ b/git.c @@ -416,23 +416,13 @@ static void execv_dashed_external(const char **argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; - char *slash = (char *)cmd + strlen(cmd); + const char *cmd; int done_alias = 0; - /* - * Take the basename of argv[0] as the command - * name, and the dirname as the default exec_path - * if we don't have anything better. - */ - do - --slash; - while (cmd <= slash && !is_dir_sep(*slash)); - if (cmd <= slash) { - *slash++ = 0; - git_set_argv0_path(cmd); - cmd = slash; - } + if (argv[0] && *argv[0]) + cmd = git_extract_argv0_path(argv[0]); + else + cmd = "git-help"; /* * "git-xxxx" is the same as "git xxxx", but we obviously: From 2a7e0eeb480c083fc66065a9505fbbfecae2cf4d Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 0473/3720] Glean libexec path from argv[0] for git-upload-pack and git-receive-pack. If the user specified the full path to git-upload-pack as the -u option to "git clone" when cloning a remote repository, and git was not on the default PATH on the remote machine, git-upload-pack was failing to exec git-pack-objects. By making the argv[0] path (if any) available to setup_path(), this will allow finding the "git" executable in the same directory as "git-upload-pack". The default built in to exec_cmd.c is to look for "git" in the ".../libexec/git-core" directory, but it is not installed there (any longer). Much the same applies to invoking git-receive-pack from a non-PATH location using the "--exec" argument to "git push". [ spr: split Steve's original commit into two commits. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- receive-pack.c | 3 +++ upload-pack.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/receive-pack.c b/receive-pack.c index d44c19e6b5..3699b166c7 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -467,6 +467,9 @@ int main(int argc, char **argv) int i; char *dir = NULL; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + argv++; for (i = 1; i < argc; i++) { char *arg = *argv++; diff --git a/upload-pack.c b/upload-pack.c index e5adbc011e..c469a60d79 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -616,6 +616,9 @@ int main(int argc, char **argv) int i; int strict = 0; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; From 9599d567403f6a0bf185f8a3c4e14a77b69004a5 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 08:58:21 +0200 Subject: [PATCH 0474/3720] Add calls to git_extract_argv0_path() in programs that call git_config_* Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls in the programs that use git_config. --- daemon.c | 3 +++ fast-import.c | 4 ++++ hash-object.c | 4 ++++ index-pack.c | 4 ++++ unpack-file.c | 4 ++++ var.c | 4 ++++ 6 files changed, 23 insertions(+) diff --git a/daemon.c b/daemon.c index 8dcde73200..172854e74c 100644 --- a/daemon.c +++ b/daemon.c @@ -1055,6 +1055,9 @@ int main(int argc, char **argv) gid_t gid = 0; int i; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + /* Without this we cannot rely on waitpid() to tell * what happened to our children. */ diff --git a/fast-import.c b/fast-import.c index d85b3a561f..239309f96d 100644 --- a/fast-import.c +++ b/fast-import.c @@ -150,6 +150,7 @@ Format of STDIN stream: #include "refs.h" #include "csum-file.h" #include "quote.h" +#include "exec_cmd.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1<"); if (get_sha1(argv[1], sha1)) diff --git a/var.c b/var.c index f1eb314e89..33457dc6ab 100644 --- a/var.c +++ b/var.c @@ -4,6 +4,7 @@ * Copyright (C) Eric Biederman, 2005 */ #include "cache.h" +#include "exec_cmd.h" static const char var_usage[] = "git var [-l | ]"; @@ -56,6 +57,9 @@ int main(int argc, char **argv) usage(var_usage); } + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory_gently(&nongit); val = NULL; From 8327b82bf72faaa5bcf0cee176312f1f89bae1c3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 11:30:33 +0200 Subject: [PATCH 0475/3720] Modify setup_path() to only add git_exec_path() to PATH We should search git programs only in the highest-priority location. The old code added the directories "argv_exec_path", "getenv(EXEC_PATH_ENVIRONMENT)", and "system_path(GIT_EXEC_PATH)" to PATH. The same order is implemented in git_exec_path(), which returns the highest priority location to search for executables. If the user explicitly overrides the default location (by --exec-path or GIT_EXEC_PATH) we can expect that all the required programs are there. It does not make sense that only some of the required programs are located at the highest priority location and other programs are picked up from a lower priority exec-path. If exec-path is overridden a complete set of commands should be provided, otherwise several different versions might easily get mixed, which is likely to spread confusion. Accessing the location with highest priority only is also required for testing of executables built with RUNTIME_PREFIX. Calling system_path(GIT_EXEC_PATH) is avoided if a higher-priority location is provided, which is the case for the tests. The call to system_path() must be avoided, if RUNTIME_PREFIX is set, because the call would fail if the executable is not installed at its final destination. But we test before installing. --- exec_cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 46ebf7ec82..2a86670baa 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -111,9 +111,7 @@ void setup_path(void) strbuf_init(&new_path, 0); - add_path(&new_path, argv_exec_path); - add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); - add_path(&new_path, system_path(GIT_EXEC_PATH)); + add_path(&new_path, git_exec_path()); add_path(&new_path, argv0_path); if (old_path) From 1a78826c218ecf8bbda95802e8e0fc912a1d499b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:43:58 +0200 Subject: [PATCH 0476/3720] Windows: Revert to default paths and convert them by RUNTIME_PREFIX The RUNTIME_PREFIX mechanism allows us to use the default (absolute) paths on Windows too. Defining RUNTIME_PREFIX explicitly requests for translation of paths during runtime, depending on the path to the executable. --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b229bff5fb..b7c4e02d6c 100644 --- a/Makefile +++ b/Makefile @@ -755,6 +755,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 @@ -762,9 +763,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = ../libexec/git-core - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From 8ed472bcbb8a5eb47354050606129f13487c6e53 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 08:58:21 +0200 Subject: [PATCH 0477/3720] Add call to git_extract_argv0_path() to various programs Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls. --- http-push.c | 3 +++ imap-send.c | 4 ++++ merge-index.c | 4 ++++ merge-tree.c | 4 ++++ mktag.c | 4 ++++ mktree.c | 4 ++++ pack-redundant.c | 4 ++++ patch-id.c | 4 ++++ update-server-info.c | 4 ++++ 9 files changed, 35 insertions(+) diff --git a/http-push.c b/http-push.c index 6805288857..47fa1cb6b3 100644 --- a/http-push.c +++ b/http-push.c @@ -2170,6 +2170,9 @@ int main(int argc, char **argv) struct ref *ref; char *rewritten_url = NULL; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); remote = xcalloc(sizeof(*remote), 1); diff --git a/imap-send.c b/imap-send.c index 1ec1310921..6714f9114c 100644 --- a/imap-send.c +++ b/imap-send.c @@ -23,6 +23,7 @@ */ #include "cache.h" +#include "exec_cmd.h" typedef struct store_conf { char *name; @@ -1293,6 +1294,9 @@ main(int argc, char **argv) int r; int total, n = 0; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + /* init the random number generator */ arc4_init(); diff --git a/merge-index.c b/merge-index.c index 7827e87a92..5d89eadba0 100644 --- a/merge-index.c +++ b/merge-index.c @@ -1,5 +1,6 @@ #include "cache.h" #include "run-command.h" +#include "exec_cmd.h" static const char *pgm; static const char *arguments[9]; @@ -93,6 +94,9 @@ int main(int argc, char **argv) if (argc < 3) usage("git-merge-index [-o] [-q] (-a | [--] *)"); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); read_cache(); diff --git a/merge-tree.c b/merge-tree.c index 02fc10f7e6..51061ae604 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -2,6 +2,7 @@ #include "tree-walk.h" #include "xdiff-interface.h" #include "blob.h" +#include "exec_cmd.h" static const char merge_tree_usage[] = "git-merge-tree "; static int resolve_directories = 1; @@ -345,6 +346,9 @@ int main(int argc, char **argv) if (argc != 4) usage(merge_tree_usage); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); buf1 = get_tree_descriptor(t+0, argv[1]); diff --git a/mktag.c b/mktag.c index 0b34341f71..44490a6729 100644 --- a/mktag.c +++ b/mktag.c @@ -1,5 +1,6 @@ #include "cache.h" #include "tag.h" +#include "exec_cmd.h" /* * A signature file has a very simple fixed format: four lines @@ -159,6 +160,9 @@ int main(int argc, char **argv) if (argc != 1) usage("git-mktag < signaturefile"); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); strbuf_init(&buf, 0); diff --git a/mktree.c b/mktree.c index e0da110a98..0e83fc935b 100644 --- a/mktree.c +++ b/mktree.c @@ -6,6 +6,7 @@ #include "cache.h" #include "quote.h" #include "tree.h" +#include "exec_cmd.h" static struct treeent { unsigned mode; @@ -70,6 +71,9 @@ int main(int ac, char **av) unsigned char sha1[20]; int line_termination = '\n'; + if (av[0] && *av[0]) + git_extract_argv0_path(av[0]); + setup_git_directory(); while ((1 < ac) && av[1][0] == '-') { diff --git a/pack-redundant.c b/pack-redundant.c index 25b81a445c..8ff450b319 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -7,6 +7,7 @@ */ #include "cache.h" +#include "exec_cmd.h" #define BLKSIZE 512 @@ -601,6 +602,9 @@ int main(int argc, char **argv) unsigned char *sha1; char buf[42]; /* 40 byte sha1 + \n + \0 */ + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); for (i = 1; i < argc; i++) { diff --git a/patch-id.c b/patch-id.c index 9349bc5580..775e2954bd 100644 --- a/patch-id.c +++ b/patch-id.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static void flush_current_id(int patchlen, unsigned char *id, SHA_CTX *c) { @@ -79,6 +80,9 @@ int main(int argc, char **argv) if (argc != 1) usage(patch_id_usage); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + generate_id_list(); return 0; } diff --git a/update-server-info.c b/update-server-info.c index 7e8209ea4b..286a4dd517 100644 --- a/update-server-info.c +++ b/update-server-info.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static const char update_server_info_usage[] = "git update-server-info [--force]"; @@ -19,6 +20,9 @@ int main(int ac, char **av) if (i != ac) usage(update_server_info_usage); + if (av[0] && *av[0]) + git_extract_argv0_path(av[0]); + setup_git_directory(); return !!update_server_info(force); From c45c40385e07ccc067a67d408131682767015b80 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Sep 2008 08:46:30 +0200 Subject: [PATCH 0478/3720] compat/mingw: Support a timeout in the poll emulation if no fds are given Our poll() emulation did not support the timeout argument. With this patch we support it as long as poll() does not need to wait on file descriptors as well because in this case the call just amounts to Sleep(). This is needed if the user sets help.autocorrect is set to a positive value. Signed-off-by: Johannes Sixt --- compat/mingw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ccfa2a0a3d..7eed60db1b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -263,8 +263,13 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout) { int i, pending; - if (timeout != -1) + if (timeout >= 0) { + if (nfds == 0) { + Sleep(timeout); + return 0; + } return errno = EINVAL, error("poll timeout not supported"); + } /* When there is only one fd to wait for, then we pretend that * input is available and let the actual wait happen when the From 226c37e6fc8ae0aa2232ae93eeb05c92e85c121a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 7 Nov 2008 15:02:10 +0100 Subject: [PATCH 0479/3720] Revert "t3903: Mark tests as broken on MinGW" This reverts commit fe3238dc4c870cb865bd2862f317afeb35018267, which worked around the bug that stash@{1} was not transfered correctly down the command invocation chain. But this bug was fixed later, so this workaround is not necessary anymore. --- t/t3903-stash.sh | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 7cb4e177b6..7484cbede6 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -88,11 +88,7 @@ test_expect_success 'drop top stash' ' test 1 = $(git show HEAD:file) ' -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac -$test_expect 'drop middle stash' ' +test_expect_success 'drop middle stash' ' git reset --hard && echo 8 > file && git stash && @@ -112,11 +108,7 @@ $test_expect 'drop middle stash' ' test 1 = $(git show HEAD:file) ' -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac -$test_expect 'stash pop' ' +test_expect_success 'stash pop' ' git reset --hard && git stash pop && test 3 = $(cat file) && From e95a73efe91c53de473c195a0a12e1b66a726ff7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 7 Nov 2008 13:52:12 +0100 Subject: [PATCH 0480/3720] t3903-stash: Work around a racily-clean index that is not detected. We still have the problem that sometimes the time returned by stat() is off by a second into the past. As a consequence, git cannot detect when a file was modified such that only the content changed but no other aspect of the meta-data that stat() retrieves. So we artificially delay the modification so that at least the timestamp is different from the one recorded in the index. --- t/t3903-stash.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 7484cbede6..fa5de5b380 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -92,6 +92,7 @@ test_expect_success 'drop middle stash' ' git reset --hard && echo 8 > file && git stash && + sleep 1 && echo 9 > file && git stash && git stash drop stash@{1} && From 639583be9877f767dc63554666be3dfdadde2b51 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 17 Nov 2008 09:21:30 +0100 Subject: [PATCH 0481/3720] t5303: Do not use /dev/zero We do not have /dev/zero on Windows. As a work-around we use a file with a single NUL byte (because that's all that the tests need). Signed-off-by: Johannes Sixt --- t/t5303-pack-corruption-resilience.sh | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index b919db02ac..5132d41309 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -41,12 +41,6 @@ create_new_pack() { git verify-pack -v ${pack}.pack } -zeros () { - while :; do - echo -n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - done | tr x '\0' -} - do_repack() { pack=`printf "$blob_1\n$blob_2\n$blob_3\n" | git pack-objects $@ .git/objects/pack/pack` && @@ -61,6 +55,8 @@ do_corrupt_object() { test_must_fail git verify-pack ${pack}.pack } +printf '\0' > zero + test_expect_success \ 'initial setup validation' \ 'create_test_files && @@ -72,7 +68,7 @@ test_expect_success \ test_expect_success \ 'create corruption in header of first object' \ - 'do_corrupt_object $blob_1 0 < /dev/zero && + 'do_corrupt_object $blob_1 0 < zero && test_must_fail git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -131,7 +127,7 @@ test_expect_success \ 'create corruption in header of first delta' \ 'create_new_pack && git prune-packed && - do_corrupt_object $blob_2 0 < /dev/zero && + do_corrupt_object $blob_2 0 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -186,7 +182,7 @@ test_expect_success \ 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \ 'create_new_pack && git prune-packed && - do_corrupt_object $blob_2 2 < /dev/zero && + do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -213,7 +209,7 @@ test_expect_success \ 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \ 'create_new_pack --delta-base-offset && git prune-packed && - do_corrupt_object $blob_2 2 < /dev/zero && + do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -265,7 +261,7 @@ test_expect_success \ test_expect_success \ '... and a redundant pack allows for full recovery too' \ - 'do_corrupt_object $blob_2 2 < /dev/zero && + 'do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null && From 8054a9ec602701973ca4010b5d37d6ec1889ec86 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 17 Nov 2008 09:25:19 +0100 Subject: [PATCH 0482/3720] t5303: Do not overwrite an existing pack This test corrupts a pack file, then repacks the objects. The consequence is that the repacked pack file has the same name as the original file (that has been corrupted). During its operation, git-pack-objects opens the corrupted file and keeps it open at all times. On Windows, this is a problem because a file that is open in any process cannot be delete or replaced, but that is what we do in some of the test cases, and so they fail. The work-around is to write the repacked objects to a file of a different name, and replace the original after git-pack-objects has terminated. Signed-off-by: Johannes Sixt --- t/t5303-pack-corruption-resilience.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 5132d41309..41c83e3477 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -43,8 +43,11 @@ create_new_pack() { do_repack() { pack=`printf "$blob_1\n$blob_2\n$blob_3\n" | - git pack-objects $@ .git/objects/pack/pack` && - pack=".git/objects/pack/pack-${pack}" + git pack-objects $@ .git/objects/pack/packtmp` && + packtmp=".git/objects/pack/packtmp-${pack}" && + pack=".git/objects/pack/pack-${pack}" && + mv "${packtmp}.pack" "${pack}.pack" && + mv "${packtmp}.idx" "${pack}.idx" } do_corrupt_object() { From e12c7f1492cce63377ff393cb5cc60ef5aa80d63 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 19 Nov 2008 16:16:42 +0100 Subject: [PATCH 0483/3720] compat/mingw.c: Teach mingw_rename() to replace read-only files On POSIX, rename() can replace files that are not writable. On Windows, however, read-only files cannot be replaced without additional efforts: We have to make the destination writable first. Since the situations where the destination is read-only are rare, we do not make the destination writable on every invocation, but only if the first try to rename a file failed with an "access denied" error. Signed-off-by: Johannes Sixt --- compat/mingw.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index b534a8a472..3dbe6a77ff 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -819,6 +819,8 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) #undef rename int mingw_rename(const char *pold, const char *pnew) { + DWORD attrs; + /* * Try native rename() first to get errno right. * It is based on MoveFile(), which cannot overwrite existing files. @@ -830,12 +832,19 @@ int mingw_rename(const char *pold, const char *pnew) if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ - if (GetLastError() == ERROR_ACCESS_DENIED) { - DWORD attrs = GetFileAttributes(pnew); - if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { + if (GetLastError() == ERROR_ACCESS_DENIED && + (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { + if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; return -1; } + if ((attrs & FILE_ATTRIBUTE_READONLY) && + SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { + if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) + return 0; + /* revert file attributes on failure */ + SetFileAttributes(pnew, attrs); + } } errno = EACCES; return -1; From d4654ac4b47a1fa0cb5537d0819eb86ba5bd3a18 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 10 Dec 2008 08:37:59 +0100 Subject: [PATCH 0484/3720] Revert "t5303: Do not overwrite an existing pack" This reverts commit 8054a9ec602701973ca4010b5d37d6ec1889ec86. --- t/t5303-pack-corruption-resilience.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 41c83e3477..5132d41309 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -43,11 +43,8 @@ create_new_pack() { do_repack() { pack=`printf "$blob_1\n$blob_2\n$blob_3\n" | - git pack-objects $@ .git/objects/pack/packtmp` && - packtmp=".git/objects/pack/packtmp-${pack}" && - pack=".git/objects/pack/pack-${pack}" && - mv "${packtmp}.pack" "${pack}.pack" && - mv "${packtmp}.idx" "${pack}.idx" + git pack-objects $@ .git/objects/pack/pack` && + pack=".git/objects/pack/pack-${pack}" } do_corrupt_object() { From 2fb7da977b49fbe81eeb074c277010759988a681 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Dec 2008 16:08:58 +0100 Subject: [PATCH 0485/3720] Skip tests that involve symbolic links. Signed-off-by: Johannes Sixt --- t/t2300-cd-to-toplevel.sh | 6 ++++++ t/t5521-pull-symlink.sh | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/t/t2300-cd-to-toplevel.sh b/t/t2300-cd-to-toplevel.sh index beddb4e9f2..14416b3210 100755 --- a/t/t2300-cd-to-toplevel.sh +++ b/t/t2300-cd-to-toplevel.sh @@ -24,6 +24,10 @@ test_cd_to_toplevel repo 'at physical root' test_cd_to_toplevel repo/sub/dir 'at physical subdir' +if test "$no_symlinks"; then + say "symbolic links not supported - skipping tests" +else + ln -s repo symrepo test_cd_to_toplevel symrepo 'at symbolic root' @@ -34,4 +38,6 @@ cd repo ln -s sub/dir internal-link test_cd_to_toplevel internal-link 'at internal symbolic subdir' +fi # $no_symlinks + test_done diff --git a/t/t5521-pull-symlink.sh b/t/t5521-pull-symlink.sh index 5672b51e2e..88583bfc9f 100755 --- a/t/t5521-pull-symlink.sh +++ b/t/t5521-pull-symlink.sh @@ -4,6 +4,11 @@ test_description='pulling from symlinked subdir' . ./test-lib.sh +if test "$no_symlinks"; then + say "symbolic links not supported - skipping tests" + test_done +fi + # The scenario we are building: # # trash\ directory/ From ee10a9759a22a9a8885761436049ceaefc0b8086 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 10 Aug 2008 17:52:36 +0200 Subject: [PATCH 0486/3720] Move computation of absolute paths from Makefile to runtime and compute prefix on the fly if RUNTIME_PREFIX set This is the first commit of a series that adds support for relocatable binaries (called RUNTIME_PREFIX). Such binaries can be moved together with the system configuration files to a different directory, as long as the relative paths from the binary to the configuration files stays the same. This functionality is essential on Windows where we deliver git binaries with an installer that allows to freely choose the installation location. The commit series implements RUNTIME_PREFIX only on Windows. The architecture is such that adding support on Unix should not be too hard. This first commits makes all paths relative in the Makefile and teaches system_path() to add the prefix instead. We used to compute absolute paths in the Makefile and passed them to C as defines. We now pass relative paths to C and call system_path() to add the prefix at runtime. If RUNTIME_PREFIX is unset we use the static prefix. This will be the default on Unix. Thus, the behavior is unchanged compared to the old implementation. If RUNTIME_PREFIX is set the prefix is computed from the location of the executable. In this case, system_path() tries to strip known directories that executables can be located in from the path of the executable. If the path is successfully stripped it is used as the prefix. For example, if the executable is "/msysgit/bin/git" and BINDIR is "bin", then the prefix computed is "/msysgit". If the runtime prefix computation fails, we fall back to the static prefix specified in the makefile. This can be the case if the executable is not installed at a known location. Note that our test system sets GIT_CONFIG_NOSYSTEM to tell git to ignore global configuration files during testing. Hence testing does not trigger the fall back. Note that the implementation requires argv0_path to be set to an absolute path, which is currently the case only on Windows. argv0_path must point to the directory of the executable. We use assert() to verify this during debugging. On Windows, the wrapper for main() (see compat/mingw.h) guarantees that this is the case. On Unix, further work is required before RUNTIME_PREFIX can be enabled. --- Makefile | 45 ++++++++++++++++++++++++++--------------- builtin-help.c | 4 ++-- exec_cmd.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index aabf0130b9..da17fe950a 100644 --- a/Makefile +++ b/Makefile @@ -179,28 +179,32 @@ STRIP ?= strip # Among the variables below, these: # gitexecdir # template_dir +# mandir +# infodir # htmldir # ETC_GITCONFIG (but not sysconfdir) -# can be specified as a relative path ../some/where/else (which must begin -# with ../); this is interpreted as relative to $(bindir) and "git" at +# can be specified as a relative path some/where/else; +# this is interpreted as relative to $(prefix) and "git" at # runtime figures out where they are based on the path to the executable. # This can help installing the suite in a relocatable way. prefix = $(HOME) -bindir = $(prefix)/bin -mandir = $(prefix)/share/man -infodir = $(prefix)/share/info -gitexecdir = $(prefix)/libexec/git-core +bindir_relative = bin +bindir = $(prefix)/$(bindir_relative) +mandir = share/man +infodir = share/info +gitexecdir = libexec/git-core sharedir = $(prefix)/share -template_dir = $(sharedir)/git-core/templates -htmldir=$(sharedir)/doc/git-doc +template_dir = share/git-core/templates +htmldir = share/doc/git-doc ifeq ($(prefix),/usr) sysconfdir = /etc +ETC_GITCONFIG = $(sysconfdir)/gitconfig else sysconfdir = $(prefix)/etc +ETC_GITCONFIG = etc/gitconfig endif lib = lib -ETC_GITCONFIG = $(sysconfdir)/gitconfig # DESTDIR= # default configuration for gitweb @@ -1027,6 +1031,9 @@ ifdef INTERNAL_QSORT COMPAT_CFLAGS += -DINTERNAL_QSORT COMPAT_OBJS += compat/qsort.o endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif ifdef NO_PTHREADS THREADED_DELTA_SEARCH = @@ -1086,6 +1093,7 @@ ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) +bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) mandir_SQ = $(subst ','\'',$(mandir)) infodir_SQ = $(subst ','\'',$(infodir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) @@ -1251,7 +1259,12 @@ git.o git.spec \ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< exec_cmd.o: exec_cmd.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ + '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \ + '-DBINDIR="$(bindir_relative_SQ)"' \ + '-DPREFIX="$(prefix_SQ)"' \ + $< + builtin-init-db.o: builtin-init-db.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< @@ -1397,17 +1410,17 @@ remove-dashes: ### Installation rules -ifeq ($(firstword $(subst /, ,$(template_dir))),..) -template_instdir = $(bindir)/$(template_dir) -else +ifeq ($(abspath $(template_dir)),$(template_dir)) template_instdir = $(template_dir) +else +template_instdir = $(prefix)/$(template_dir) endif export template_instdir -ifeq ($(firstword $(subst /, ,$(gitexecdir))),..) -gitexec_instdir = $(bindir)/$(gitexecdir) -else +ifeq ($(abspath $(gitexecdir)),$(gitexecdir)) gitexec_instdir = $(gitexecdir) +else +gitexec_instdir = $(prefix)/$(gitexecdir) endif gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir)) export gitexec_instdir diff --git a/builtin-help.c b/builtin-help.c index f076efa921..9b57a74618 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -329,7 +329,7 @@ static void setup_man_path(void) * old_path, the ':' at the end will let 'man' to try * system-wide paths after ours to find the manual page. If * there is old_path, we need ':' as delimiter. */ - strbuf_addstr(&new_path, GIT_MAN_PATH); + strbuf_addstr(&new_path, system_path(GIT_MAN_PATH)); strbuf_addch(&new_path, ':'); if (old_path) strbuf_addstr(&new_path, old_path); @@ -375,7 +375,7 @@ static void show_man_page(const char *git_cmd) static void show_info_page(const char *git_cmd) { const char *page = cmd_to_page(git_cmd); - setenv("INFOPATH", GIT_INFO_PATH, 1); + setenv("INFOPATH", system_path(GIT_INFO_PATH), 1); execlp("info", "info", "gitman", page, NULL); } diff --git a/exec_cmd.c b/exec_cmd.c index cdd35f9195..669b82e35a 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,11 +9,57 @@ static const char *argv0_path; const char *system_path(const char *path) { - if (!is_absolute_path(path) && argv0_path) { - struct strbuf d = STRBUF_INIT; - strbuf_addf(&d, "%s/%s", argv0_path, path); - path = strbuf_detach(&d, NULL); + static const char *prefix; + + if (is_absolute_path(path)) { + return path; } + +#ifdef RUNTIME_PREFIX + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix) { + const char *strip[] = { + GIT_EXEC_PATH, + BINDIR, + 0 + }; + const char **s; + + for (s = strip; *s; s++) { + const char *sargv = argv0_path + strlen(argv0_path); + const char *ss = *s + strlen(*s); + while (argv0_path < sargv && *s < ss + && (*sargv == *ss || + (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { + sargv--; + ss--; + } + if (*s == ss) { + struct strbuf d = STRBUF_INIT; + /* We also skip the trailing directory separator. */ + assert(sargv - argv0_path - 1 >= 0); + strbuf_add(&d, argv0_path, sargv - argv0_path - 1); + prefix = strbuf_detach(&d, NULL); + break; + } + } + } + + if (!prefix) { + prefix = PREFIX; + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); + } +#else + prefix = PREFIX; +#endif + + struct strbuf d = STRBUF_INIT; + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); return path; } From 7501e1c7089414ec414dec8b2c95840ba6c95813 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 0487/3720] Refactor git_set_argv0_path() to git_extract_argv0_path() This commit moves the code that computes the dirname of argv[0] from git.c's main() to git_set_argv0_path() and renames the function to git_extract_argv0_path(). This makes the code in git.c's main less cluttered, and we can use the dirname computation from other main() functions too. [spr: split Steve's original commit and wrote new commit message. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- exec_cmd.c | 15 +++++++++++++-- exec_cmd.h | 2 +- git.c | 20 +++++--------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 669b82e35a..dde5cfd14f 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -63,9 +63,20 @@ const char *system_path(const char *path) return path; } -void git_set_argv0_path(const char *path) +const char *git_extract_argv0_path(const char *argv0) { - argv0_path = path; + const char *slash = argv0 + strlen(argv0); + + do + --slash; + while (slash >= argv0 && !is_dir_sep(*slash)); + + if (slash >= argv0) { + argv0_path = xstrndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; } void git_set_argv_exec_path(const char *exec_path) diff --git a/exec_cmd.h b/exec_cmd.h index 594f961387..392e9032c3 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -2,7 +2,7 @@ #define GIT_EXEC_CMD_H extern void git_set_argv_exec_path(const char *exec_path); -extern void git_set_argv0_path(const char *path); +extern const char* git_extract_argv0_path(const char *path); extern const char* git_exec_path(void); extern void setup_path(void); extern const char **prepare_git_cmd(const char **argv); diff --git a/git.c b/git.c index 940a498962..6c3595decc 100644 --- a/git.c +++ b/git.c @@ -419,23 +419,13 @@ static void execv_dashed_external(const char **argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; - char *slash = (char *)cmd + strlen(cmd); + const char *cmd; int done_alias = 0; - /* - * Take the basename of argv[0] as the command - * name, and the dirname as the default exec_path - * if we don't have anything better. - */ - do - --slash; - while (cmd <= slash && !is_dir_sep(*slash)); - if (cmd <= slash) { - *slash++ = 0; - git_set_argv0_path(cmd); - cmd = slash; - } + if (argv[0] && *argv[0]) + cmd = git_extract_argv0_path(argv[0]); + else + cmd = "git-help"; /* * "git-xxxx" is the same as "git xxxx", but we obviously: From ea476195ab8c45e123302ec5481274f59d11d38c Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 0488/3720] Glean libexec path from argv[0] for git-upload-pack and git-receive-pack. If the user specified the full path to git-upload-pack as the -u option to "git clone" when cloning a remote repository, and git was not on the default PATH on the remote machine, git-upload-pack was failing to exec git-pack-objects. By making the argv[0] path (if any) available to setup_path(), this will allow finding the "git" executable in the same directory as "git-upload-pack". The default built in to exec_cmd.c is to look for "git" in the ".../libexec/git-core" directory, but it is not installed there (any longer). Much the same applies to invoking git-receive-pack from a non-PATH location using the "--exec" argument to "git push". [ spr: split Steve's original commit into two commits. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- builtin-receive-pack.c | 3 +++ upload-pack.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index db67c3162c..bbedcfe5e4 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -579,6 +579,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) int i; char *dir = NULL; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + argv++; for (i = 1; i < argc; i++) { const char *arg = *argv++; diff --git a/upload-pack.c b/upload-pack.c index e5adbc011e..c469a60d79 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -616,6 +616,9 @@ int main(int argc, char **argv) int i; int strict = 0; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; From 61cc52a1ccfd426af3523d681dec63a8fa7c2842 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 08:58:21 +0200 Subject: [PATCH 0489/3720] Add calls to git_extract_argv0_path() in programs that call git_config_* Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls. --- daemon.c | 3 +++ fast-import.c | 4 ++++ hash-object.c | 4 ++++ http-push.c | 3 +++ imap-send.c | 4 ++++ index-pack.c | 4 ++++ merge-index.c | 4 ++++ merge-tree.c | 4 ++++ mktag.c | 4 ++++ mktree.c | 4 ++++ pack-redundant.c | 4 ++++ patch-id.c | 4 ++++ unpack-file.c | 4 ++++ update-server-info.c | 4 ++++ var.c | 4 ++++ 15 files changed, 58 insertions(+) diff --git a/daemon.c b/daemon.c index 1cef3098d2..fed789495d 100644 --- a/daemon.c +++ b/daemon.c @@ -949,6 +949,9 @@ int main(int argc, char **argv) gid_t gid = 0; int i; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; diff --git a/fast-import.c b/fast-import.c index a6bce66196..7762205b70 100644 --- a/fast-import.c +++ b/fast-import.c @@ -150,6 +150,7 @@ Format of STDIN stream: #include "refs.h" #include "csum-file.h" #include "quote.h" +#include "exec_cmd.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1< (-a | [--] *)"); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); read_cache(); diff --git a/merge-tree.c b/merge-tree.c index 2d1413efbb..165ccfc608 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -2,6 +2,7 @@ #include "tree-walk.h" #include "xdiff-interface.h" #include "blob.h" +#include "exec_cmd.h" static const char merge_tree_usage[] = "git-merge-tree "; static int resolve_directories = 1; @@ -344,6 +345,9 @@ int main(int argc, char **argv) if (argc != 4) usage(merge_tree_usage); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); buf1 = get_tree_descriptor(t+0, argv[1]); diff --git a/mktag.c b/mktag.c index ba3d495e07..ff32f8ab04 100644 --- a/mktag.c +++ b/mktag.c @@ -1,5 +1,6 @@ #include "cache.h" #include "tag.h" +#include "exec_cmd.h" /* * A signature file has a very simple fixed format: four lines @@ -159,6 +160,9 @@ int main(int argc, char **argv) if (argc != 1) usage("git-mktag < signaturefile"); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); if (strbuf_read(&buf, 0, 4096) < 0) { diff --git a/mktree.c b/mktree.c index 514fd9b15a..8ac0d576ed 100644 --- a/mktree.c +++ b/mktree.c @@ -6,6 +6,7 @@ #include "cache.h" #include "quote.h" #include "tree.h" +#include "exec_cmd.h" static struct treeent { unsigned mode; @@ -70,6 +71,9 @@ int main(int ac, char **av) unsigned char sha1[20]; int line_termination = '\n'; + if (av[0] && *av[0]) + git_extract_argv0_path(av[0]); + setup_git_directory(); while ((1 < ac) && av[1][0] == '-') { diff --git a/pack-redundant.c b/pack-redundant.c index 25b81a445c..8ff450b319 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -7,6 +7,7 @@ */ #include "cache.h" +#include "exec_cmd.h" #define BLKSIZE 512 @@ -601,6 +602,9 @@ int main(int argc, char **argv) unsigned char *sha1; char buf[42]; /* 40 byte sha1 + \n + \0 */ + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); for (i = 1; i < argc; i++) { diff --git a/patch-id.c b/patch-id.c index 871f1d20c0..ff460e282a 100644 --- a/patch-id.c +++ b/patch-id.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static void flush_current_id(int patchlen, unsigned char *id, git_SHA_CTX *c) { @@ -79,6 +80,9 @@ int main(int argc, char **argv) if (argc != 1) usage(patch_id_usage); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + generate_id_list(); return 0; } diff --git a/unpack-file.c b/unpack-file.c index bcdc8bbb3b..f8bfda7d33 100644 --- a/unpack-file.c +++ b/unpack-file.c @@ -1,5 +1,6 @@ #include "cache.h" #include "blob.h" +#include "exec_cmd.h" static char *create_temp_file(unsigned char *sha1) { @@ -25,6 +26,9 @@ int main(int argc, char **argv) { unsigned char sha1[20]; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + if (argc != 2) usage("git-unpack-file "); if (get_sha1(argv[1], sha1)) diff --git a/update-server-info.c b/update-server-info.c index 7e8209ea4b..286a4dd517 100644 --- a/update-server-info.c +++ b/update-server-info.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static const char update_server_info_usage[] = "git update-server-info [--force]"; @@ -19,6 +20,9 @@ int main(int ac, char **av) if (i != ac) usage(update_server_info_usage); + if (av[0] && *av[0]) + git_extract_argv0_path(av[0]); + setup_git_directory(); return !!update_server_info(force); diff --git a/var.c b/var.c index f1eb314e89..33457dc6ab 100644 --- a/var.c +++ b/var.c @@ -4,6 +4,7 @@ * Copyright (C) Eric Biederman, 2005 */ #include "cache.h" +#include "exec_cmd.h" static const char var_usage[] = "git var [-l | ]"; @@ -56,6 +57,9 @@ int main(int argc, char **argv) usage(var_usage); } + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory_gently(&nongit); val = NULL; From 1b14cecc2c4acf2fef0dbd3b95e3b4dfe7246fa9 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 11:30:33 +0200 Subject: [PATCH 0490/3720] Modify setup_path() to only add git_exec_path() to PATH Searching git programs only in the highest priority location is sufficient. It does not make sense that some of the required programs are located at the highest priority location but other programs are picked up from a lower priority exec-path. If exec-path is overridden a complete set of commands should be provided, otherwise several different versions could get mixed, which is likely to cause confusion. If a user explicitly overrides the default location (by --exec-path or GIT_EXEC_PATH), we now expect that that all the required programs are found there. Instead of adding the directories "argv_exec_path", "getenv(EXEC_PATH_ENVIRONMENT)", and "system_path(GIT_EXEC_PATH)" to PATH, we now rely on git_exec_path(), which implements the same order, but only returns the highest priority location to search for executables. Accessing only the location with highest priority is also required for testing executables built with RUNTIME_PREFIX. The call to system_path() should be avoided if RUNTIME_PREFIX is set and the executable is not installed at its final destination. Because we test before installing, we want to avoid calling system_path() during tests. The modifications brought by this commit avoid calling system_path(GIT_EXEC_PATH) if a higher-priority location is provided, which is the case when running the tests. --- exec_cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index dde5cfd14f..0de03c2bed 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -118,9 +118,7 @@ void setup_path(void) const char *old_path = getenv("PATH"); struct strbuf new_path = STRBUF_INIT; - add_path(&new_path, argv_exec_path); - add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); - add_path(&new_path, system_path(GIT_EXEC_PATH)); + add_path(&new_path, git_exec_path()); add_path(&new_path, argv0_path); if (old_path) From e8d0d369da5a9bb6e76846251f27e0f384f490ec Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:43:58 +0200 Subject: [PATCH 0491/3720] Windows: Revert to default paths and convert them by RUNTIME_PREFIX The RUNTIME_PREFIX mechanism allows us to use the default (absolute) paths on Windows too. Defining RUNTIME_PREFIX explicitly requests for translation of paths during runtime, depending on the path to the executable. --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index da17fe950a..2c4a3f0285 100644 --- a/Makefile +++ b/Makefile @@ -789,6 +789,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch @@ -797,9 +798,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = ../libexec/git-core - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From d1374e7cfed6d3aa9b11b756dba54c07a12e8224 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:09 +0100 Subject: [PATCH 0492/3720] Move computation of absolute paths from Makefile to runtime (in preparation for RUNTIME_PREFIX) This commit prepares the Makefile for relocatable binaries (called RUNTIME_PREFIX). Such binaries will be able to be moved together with the system configuration files to a different directory, requiring to compute the prefix at runtime. In a first step, we make all paths relative in the Makefile and teach system_path() to add the prefix instead. We used to compute absolute paths in the Makefile and passed them to C as defines. We now pass relative paths to C and call system_path() to add the prefix at runtime. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- Makefile | 42 ++++++++++++++++++++++++++---------------- builtin-help.c | 4 ++-- exec_cmd.c | 13 ++++++++----- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 2b873fa99f..1d2060aa3f 100644 --- a/Makefile +++ b/Makefile @@ -179,28 +179,32 @@ STRIP ?= strip # Among the variables below, these: # gitexecdir # template_dir +# mandir +# infodir # htmldir # ETC_GITCONFIG (but not sysconfdir) -# can be specified as a relative path ../some/where/else (which must begin -# with ../); this is interpreted as relative to $(bindir) and "git" at +# can be specified as a relative path some/where/else; +# this is interpreted as relative to $(prefix) and "git" at # runtime figures out where they are based on the path to the executable. # This can help installing the suite in a relocatable way. prefix = $(HOME) -bindir = $(prefix)/bin -mandir = $(prefix)/share/man -infodir = $(prefix)/share/info -gitexecdir = $(prefix)/libexec/git-core +bindir_relative = bin +bindir = $(prefix)/$(bindir_relative) +mandir = share/man +infodir = share/info +gitexecdir = libexec/git-core sharedir = $(prefix)/share -template_dir = $(sharedir)/git-core/templates -htmldir=$(sharedir)/doc/git-doc +template_dir = share/git-core/templates +htmldir = share/doc/git-doc ifeq ($(prefix),/usr) sysconfdir = /etc +ETC_GITCONFIG = $(sysconfdir)/gitconfig else sysconfdir = $(prefix)/etc +ETC_GITCONFIG = etc/gitconfig endif lib = lib -ETC_GITCONFIG = $(sysconfdir)/gitconfig # DESTDIR= # default configuration for gitweb @@ -1086,6 +1090,7 @@ ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) +bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) mandir_SQ = $(subst ','\'',$(mandir)) infodir_SQ = $(subst ','\'',$(infodir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) @@ -1251,7 +1256,12 @@ git.o git.spec \ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< exec_cmd.o: exec_cmd.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ + '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \ + '-DBINDIR="$(bindir_relative_SQ)"' \ + '-DPREFIX="$(prefix_SQ)"' \ + $< + builtin-init-db.o: builtin-init-db.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< @@ -1407,17 +1417,17 @@ remove-dashes: ### Installation rules -ifeq ($(firstword $(subst /, ,$(template_dir))),..) -template_instdir = $(bindir)/$(template_dir) -else +ifeq ($(abspath $(template_dir)),$(template_dir)) template_instdir = $(template_dir) +else +template_instdir = $(prefix)/$(template_dir) endif export template_instdir -ifeq ($(firstword $(subst /, ,$(gitexecdir))),..) -gitexec_instdir = $(bindir)/$(gitexecdir) -else +ifeq ($(abspath $(gitexecdir)),$(gitexecdir)) gitexec_instdir = $(gitexecdir) +else +gitexec_instdir = $(prefix)/$(gitexecdir) endif gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir)) export gitexec_instdir diff --git a/builtin-help.c b/builtin-help.c index f076efa921..9b57a74618 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -329,7 +329,7 @@ static void setup_man_path(void) * old_path, the ':' at the end will let 'man' to try * system-wide paths after ours to find the manual page. If * there is old_path, we need ':' as delimiter. */ - strbuf_addstr(&new_path, GIT_MAN_PATH); + strbuf_addstr(&new_path, system_path(GIT_MAN_PATH)); strbuf_addch(&new_path, ':'); if (old_path) strbuf_addstr(&new_path, old_path); @@ -375,7 +375,7 @@ static void show_man_page(const char *git_cmd) static void show_info_page(const char *git_cmd) { const char *page = cmd_to_page(git_cmd); - setenv("INFOPATH", GIT_INFO_PATH, 1); + setenv("INFOPATH", system_path(GIT_INFO_PATH), 1); execlp("info", "info", "gitman", page, NULL); } diff --git a/exec_cmd.c b/exec_cmd.c index cdd35f9195..114d6389e4 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,11 +9,14 @@ static const char *argv0_path; const char *system_path(const char *path) { - if (!is_absolute_path(path) && argv0_path) { - struct strbuf d = STRBUF_INIT; - strbuf_addf(&d, "%s/%s", argv0_path, path); - path = strbuf_detach(&d, NULL); - } + static const char *prefix = PREFIX; + struct strbuf d = STRBUF_INIT; + + if (is_absolute_path(path)) + return path; + + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); return path; } From ae990d02111c43771cb1c5595a97e670850860e8 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Sun, 18 Jan 2009 13:00:10 +0100 Subject: [PATCH 0493/3720] Refactor git_set_argv0_path() to git_extract_argv0_path() This commit moves the code that computes the dirname of argv[0] from git.c's main() to git_set_argv0_path() and renames the function to git_extract_argv0_path(). This makes the code in git.c's main less cluttered, and we can use the dirname computation from other main() functions too. [ spr: - split Steve's original commit and wrote new commit message. - Integrated Johannes Schindelin's cca1704897e7fdb182f68d4c48a437c5d7bc5203 while rebasing onto master. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- exec_cmd.c | 14 ++++++++++++-- exec_cmd.h | 4 ++-- git.c | 19 +++++-------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 114d6389e4..e508f1e66d 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -20,9 +20,19 @@ const char *system_path(const char *path) return path; } -void git_set_argv0_path(const char *path) +const char *git_extract_argv0_path(const char *argv0) { - argv0_path = path; + const char *slash = argv0 + strlen(argv0); + + while (argv0 <= slash && !is_dir_sep(*slash)) + slash--; + + if (slash >= argv0) { + argv0_path = xstrndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; } void git_set_argv_exec_path(const char *exec_path) diff --git a/exec_cmd.h b/exec_cmd.h index 594f961387..e2b546b615 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -2,8 +2,8 @@ #define GIT_EXEC_CMD_H extern void git_set_argv_exec_path(const char *exec_path); -extern void git_set_argv0_path(const char *path); -extern const char* git_exec_path(void); +extern const char *git_extract_argv0_path(const char *path); +extern const char *git_exec_path(void); extern void setup_path(void); extern const char **prepare_git_cmd(const char **argv); extern int execv_git_cmd(const char **argv); /* NULL terminated */ diff --git a/git.c b/git.c index ecc8fad09a..bf21e21cef 100644 --- a/git.c +++ b/git.c @@ -442,21 +442,12 @@ static int run_argv(int *argcp, const char ***argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; - char *slash = (char *)cmd + strlen(cmd); + const char *cmd; - /* - * Take the basename of argv[0] as the command - * name, and the dirname as the default exec_path - * if we don't have anything better. - */ - while (cmd <= slash && !is_dir_sep(*slash)) - slash--; - if (cmd <= slash) { - *slash++ = 0; - git_set_argv0_path(cmd); - cmd = slash; - } + if (argv[0] && *argv[0]) + cmd = git_extract_argv0_path(argv[0]); + else + cmd = "git-help"; /* * "git-xxxx" is the same as "git xxxx", but we obviously: From ba5c90c3e8956a0f4d6f2fcb63d5d1864c127b4c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:11 +0100 Subject: [PATCH 0494/3720] git_extract_argv0_path(): Move check for valid argv0 from caller to callee This simplifies the calling code. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- exec_cmd.c | 6 +++++- git.c | 5 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index e508f1e66d..f8f416b646 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -22,7 +22,11 @@ const char *system_path(const char *path) const char *git_extract_argv0_path(const char *argv0) { - const char *slash = argv0 + strlen(argv0); + const char *slash; + + if (!argv0 || !*argv0) + return NULL; + slash = argv0 + strlen(argv0); while (argv0 <= slash && !is_dir_sep(*slash)) slash--; diff --git a/git.c b/git.c index bf21e21cef..320cb43564 100644 --- a/git.c +++ b/git.c @@ -444,9 +444,8 @@ int main(int argc, const char **argv) { const char *cmd; - if (argv[0] && *argv[0]) - cmd = git_extract_argv0_path(argv[0]); - else + cmd = git_extract_argv0_path(argv[0]); + if (!cmd) cmd = "git-help"; /* From bbcd2c22f2ca74b5091b81d59b76da5b17429580 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:12 +0100 Subject: [PATCH 0495/3720] Add calls to git_extract_argv0_path() in programs that call git_config_* Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- daemon.c | 2 ++ fast-import.c | 3 +++ hash-object.c | 3 +++ http-push.c | 2 ++ imap-send.c | 3 +++ index-pack.c | 3 +++ merge-index.c | 3 +++ merge-tree.c | 3 +++ mktag.c | 3 +++ mktree.c | 3 +++ pack-redundant.c | 3 +++ patch-id.c | 3 +++ unpack-file.c | 3 +++ update-server-info.c | 3 +++ upload-pack.c | 2 ++ var.c | 3 +++ 16 files changed, 45 insertions(+) diff --git a/daemon.c b/daemon.c index 540700ee84..d93cf960f9 100644 --- a/daemon.c +++ b/daemon.c @@ -937,6 +937,8 @@ int main(int argc, char **argv) gid_t gid = 0; int i; + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; diff --git a/fast-import.c b/fast-import.c index f0e08aca70..1935206be0 100644 --- a/fast-import.c +++ b/fast-import.c @@ -150,6 +150,7 @@ Format of STDIN stream: #include "refs.h" #include "csum-file.h" #include "quote.h" +#include "exec_cmd.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1< (-a | [--] *)"); + git_extract_argv0_path(argv[0]); + setup_git_directory(); read_cache(); diff --git a/merge-tree.c b/merge-tree.c index 2d1413efbb..f18201acdb 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -2,6 +2,7 @@ #include "tree-walk.h" #include "xdiff-interface.h" #include "blob.h" +#include "exec_cmd.h" static const char merge_tree_usage[] = "git-merge-tree "; static int resolve_directories = 1; @@ -344,6 +345,8 @@ int main(int argc, char **argv) if (argc != 4) usage(merge_tree_usage); + git_extract_argv0_path(argv[0]); + setup_git_directory(); buf1 = get_tree_descriptor(t+0, argv[1]); diff --git a/mktag.c b/mktag.c index ba3d495e07..6d5083eaf0 100644 --- a/mktag.c +++ b/mktag.c @@ -1,5 +1,6 @@ #include "cache.h" #include "tag.h" +#include "exec_cmd.h" /* * A signature file has a very simple fixed format: four lines @@ -159,6 +160,8 @@ int main(int argc, char **argv) if (argc != 1) usage("git-mktag < signaturefile"); + git_extract_argv0_path(argv[0]); + setup_git_directory(); if (strbuf_read(&buf, 0, 4096) < 0) { diff --git a/mktree.c b/mktree.c index 514fd9b15a..6283bc3d43 100644 --- a/mktree.c +++ b/mktree.c @@ -6,6 +6,7 @@ #include "cache.h" #include "quote.h" #include "tree.h" +#include "exec_cmd.h" static struct treeent { unsigned mode; @@ -70,6 +71,8 @@ int main(int ac, char **av) unsigned char sha1[20]; int line_termination = '\n'; + git_extract_argv0_path(av[0]); + setup_git_directory(); while ((1 < ac) && av[1][0] == '-') { diff --git a/pack-redundant.c b/pack-redundant.c index e93eb966e2..48a12bc135 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -7,6 +7,7 @@ */ #include "cache.h" +#include "exec_cmd.h" #define BLKSIZE 512 @@ -601,6 +602,8 @@ int main(int argc, char **argv) unsigned char *sha1; char buf[42]; /* 40 byte sha1 + \n + \0 */ + git_extract_argv0_path(argv[0]); + setup_git_directory(); for (i = 1; i < argc; i++) { diff --git a/patch-id.c b/patch-id.c index 871f1d20c0..3660ad461d 100644 --- a/patch-id.c +++ b/patch-id.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static void flush_current_id(int patchlen, unsigned char *id, git_SHA_CTX *c) { @@ -79,6 +80,8 @@ int main(int argc, char **argv) if (argc != 1) usage(patch_id_usage); + git_extract_argv0_path(argv[0]); + generate_id_list(); return 0; } diff --git a/unpack-file.c b/unpack-file.c index bcdc8bbb3b..6dd8ad02fb 100644 --- a/unpack-file.c +++ b/unpack-file.c @@ -1,5 +1,6 @@ #include "cache.h" #include "blob.h" +#include "exec_cmd.h" static char *create_temp_file(unsigned char *sha1) { @@ -25,6 +26,8 @@ int main(int argc, char **argv) { unsigned char sha1[20]; + git_extract_argv0_path(argv[0]); + if (argc != 2) usage("git-unpack-file "); if (get_sha1(argv[1], sha1)) diff --git a/update-server-info.c b/update-server-info.c index 7e8209ea4b..7b38fd867b 100644 --- a/update-server-info.c +++ b/update-server-info.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static const char update_server_info_usage[] = "git update-server-info [--force]"; @@ -19,6 +20,8 @@ int main(int ac, char **av) if (i != ac) usage(update_server_info_usage); + git_extract_argv0_path(av[0]); + setup_git_directory(); return !!update_server_info(force); diff --git a/upload-pack.c b/upload-pack.c index e5adbc011e..5db6f93955 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -616,6 +616,8 @@ int main(int argc, char **argv) int i; int strict = 0; + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; diff --git a/var.c b/var.c index f1eb314e89..7362ed8735 100644 --- a/var.c +++ b/var.c @@ -4,6 +4,7 @@ * Copyright (C) Eric Biederman, 2005 */ #include "cache.h" +#include "exec_cmd.h" static const char var_usage[] = "git var [-l | ]"; @@ -56,6 +57,8 @@ int main(int argc, char **argv) usage(var_usage); } + git_extract_argv0_path(argv[0]); + setup_git_directory_gently(&nongit); val = NULL; From c9c57cd1e34508e434893ad90d2ed033ebb706ee Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:13 +0100 Subject: [PATCH 0496/3720] Modify setup_path() to only add git_exec_path() to PATH Searching git programs only in the highest priority location is sufficient. It does not make sense that some of the required programs are located at the highest priority location but other programs are picked up from a lower priority exec-path. If exec-path is overridden a complete set of commands should be provided, otherwise several different versions could get mixed, which is likely to cause confusion. If a user explicitly overrides the default location (by --exec-path or GIT_EXEC_PATH), we now expect that all the required programs are found there. Instead of adding the directories "argv_exec_path", "getenv(EXEC_PATH_ENVIRONMENT)", and "system_path(GIT_EXEC_PATH)" to PATH, we now rely on git_exec_path(), which implements the same order, but only returns the highest priority location to search for executables. Accessing only the location with highest priority is also required for testing executables built with RUNTIME_PREFIX. The call to system_path() should be avoided if RUNTIME_PREFIX is set and the executable is not installed at its final destination. Because we test before installing, we want to avoid calling system_path() during tests. The modifications in this commit avoid calling system_path(GIT_EXEC_PATH) if a higher-priority location is provided, which is the case when running the tests. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- exec_cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index f8f416b646..23f4873b2b 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -78,9 +78,7 @@ void setup_path(void) const char *old_path = getenv("PATH"); struct strbuf new_path = STRBUF_INIT; - add_path(&new_path, argv_exec_path); - add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); - add_path(&new_path, system_path(GIT_EXEC_PATH)); + add_path(&new_path, git_exec_path()); add_path(&new_path, argv0_path); if (old_path) From 1f661e93301856bac94588d534414dad6b1d5a72 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:14 +0100 Subject: [PATCH 0497/3720] Compute prefix at runtime if RUNTIME_PREFIX is set This commit adds support for relocatable binaries (called RUNTIME_PREFIX). Such binaries can be moved together with the system configuration files to a different directory, as long as the relative paths from the binary to the configuration files is preserved. This functionality is essential on Windows where we deliver git binaries with an installer that allows to freely choose the installation location. If RUNTIME_PREFIX is unset we use the static prefix. This will be the default on Unix. Thus, the behavior on Unix will remain identical to the old implementation, which used to add the prefix in the Makefile. If RUNTIME_PREFIX is set the prefix is computed from the location of the executable. In this case, system_path() tries to strip known directories that executables can be located in from the path of the executable. If the path is successfully stripped it is used as the prefix. For example, if the executable is "/msysgit/bin/git" and BINDIR is "bin", then the prefix computed is "/msysgit". If the runtime prefix computation fails, we fall back to the static prefix specified in the makefile. This can be the case if the executable is not installed at a known location. Note that our test system sets GIT_CONFIG_NOSYSTEM to tell git to ignore global configuration files during testing. Hence testing does not trigger the fall back. Note that RUNTIME_PREFIX only works on Windows, though adding support on Unix should not be too hard. The implementation requires argv0_path to be set to an absolute path. argv0_path must point to the directory of the executable. We use assert() to verify this in debug builds. On Windows, the wrapper for main() (see compat/mingw.h) guarantees that argv0_path is correctly initialized. On Unix, further work is required before RUNTIME_PREFIX can be enabled. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- Makefile | 3 +++ exec_cmd.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/Makefile b/Makefile index 1d2060aa3f..fbe52c9c6d 100644 --- a/Makefile +++ b/Makefile @@ -1031,6 +1031,9 @@ ifdef INTERNAL_QSORT COMPAT_CFLAGS += -DINTERNAL_QSORT COMPAT_OBJS += compat/qsort.o endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif ifdef NO_PTHREADS THREADED_DELTA_SEARCH = diff --git a/exec_cmd.c b/exec_cmd.c index 23f4873b2b..f234066def 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,12 +9,56 @@ static const char *argv0_path; const char *system_path(const char *path) { +#ifdef RUNTIME_PREFIX + static const char *prefix; +#else static const char *prefix = PREFIX; +#endif struct strbuf d = STRBUF_INIT; if (is_absolute_path(path)) return path; +#ifdef RUNTIME_PREFIX + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix) { + const char *strip[] = { + GIT_EXEC_PATH, + BINDIR, + 0 + }; + const char **s; + + for (s = strip; *s; s++) { + const char *sargv = argv0_path + strlen(argv0_path); + const char *ss = *s + strlen(*s); + while (argv0_path < sargv && *s < ss + && (*sargv == *ss || + (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { + sargv--; + ss--; + } + if (*s == ss) { + struct strbuf d = STRBUF_INIT; + /* We also skip the trailing directory separator. */ + assert(sargv - argv0_path - 1 >= 0); + strbuf_add(&d, argv0_path, sargv - argv0_path - 1); + prefix = strbuf_detach(&d, NULL); + break; + } + } + } + + if (!prefix) { + prefix = PREFIX; + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); + } +#endif + strbuf_addf(&d, "%s/%s", prefix, path); path = strbuf_detach(&d, NULL); return path; From db384c91a0f8ce48c24342eab7a8d0c27824cad6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:15 +0100 Subject: [PATCH 0498/3720] Windows: Revert to default paths and convert them by RUNTIME_PREFIX The RUNTIME_PREFIX mechanism allows us to use the default paths on Windows too. Defining RUNTIME_PREFIX explicitly requests for translation of paths relative to the executable at runtime. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fbe52c9c6d..74ecd77f33 100644 --- a/Makefile +++ b/Makefile @@ -789,6 +789,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch @@ -797,9 +798,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = ../libexec/git-core - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From d439f6092dff6a5ef9615458addb45eecaf1fa44 Mon Sep 17 00:00:00 2001 From: Petr Kodl Date: Sat, 24 Jan 2009 15:04:39 +0100 Subject: [PATCH 0499/3720] hardlink implementation for mingw Signed-off-by: Johannes Schindelin --- compat/mingw.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++ compat/mingw.h | 3 +- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index e25cb4fb23..869bd4acbe 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1003,3 +1003,138 @@ void mingw_open_html(const char *unixpath) printf("Launching default browser to display HTML ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } + +static int err_win_to_posix(DWORD winerr) +{ + int error = ENOSYS; + switch(winerr) { + case ERROR_ACCESS_DENIED: error = EACCES; break; + case ERROR_ACCOUNT_DISABLED: error = EACCES; break; + case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break; + case ERROR_ALREADY_ASSIGNED: error = EBUSY; break; + case ERROR_ALREADY_EXISTS: error = EEXIST; break; + case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break; + case ERROR_BAD_COMMAND: error = EIO; break; + case ERROR_BAD_DEVICE: error = ENODEV; break; + case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break; + case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break; + case ERROR_BAD_FORMAT: error = ENOEXEC; break; + case ERROR_BAD_LENGTH: error = EINVAL; break; + case ERROR_BAD_PATHNAME: error = ENOENT; break; + case ERROR_BAD_PIPE: error = EPIPE; break; + case ERROR_BAD_UNIT: error = ENODEV; break; + case ERROR_BAD_USERNAME: error = EINVAL; break; + case ERROR_BROKEN_PIPE: error = EPIPE; break; + case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break; + case ERROR_BUSY: error = EBUSY; break; + case ERROR_BUSY_DRIVE: error = EBUSY; break; + case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break; + case ERROR_CANNOT_MAKE: error = EACCES; break; + case ERROR_CANTOPEN: error = EIO; break; + case ERROR_CANTREAD: error = EIO; break; + case ERROR_CANTWRITE: error = EIO; break; + case ERROR_CRC: error = EIO; break; + case ERROR_CURRENT_DIRECTORY: error = EACCES; break; + case ERROR_DEVICE_IN_USE: error = EBUSY; break; + case ERROR_DEV_NOT_EXIST: error = ENODEV; break; + case ERROR_DIRECTORY: error = EINVAL; break; + case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break; + case ERROR_DISK_CHANGE: error = EIO; break; + case ERROR_DISK_FULL: error = ENOSPC; break; + case ERROR_DRIVE_LOCKED: error = EBUSY; break; + case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break; + case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break; + case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break; + case ERROR_FILE_EXISTS: error = EEXIST; break; + case ERROR_FILE_INVALID: error = ENODEV; break; + case ERROR_FILE_NOT_FOUND: error = ENOENT; break; + case ERROR_GEN_FAILURE: error = EIO; break; + case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break; + case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break; + case ERROR_INVALID_ACCESS: error = EACCES; break; + case ERROR_INVALID_ADDRESS: error = EFAULT; break; + case ERROR_INVALID_BLOCK: error = EFAULT; break; + case ERROR_INVALID_DATA: error = EINVAL; break; + case ERROR_INVALID_DRIVE: error = ENODEV; break; + case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break; + case ERROR_INVALID_FLAGS: error = EINVAL; break; + case ERROR_INVALID_FUNCTION: error = ENOSYS; break; + case ERROR_INVALID_HANDLE: error = EBADF; break; + case ERROR_INVALID_LOGON_HOURS: error = EACCES; break; + case ERROR_INVALID_NAME: error = EINVAL; break; + case ERROR_INVALID_OWNER: error = EINVAL; break; + case ERROR_INVALID_PARAMETER: error = EINVAL; break; + case ERROR_INVALID_PASSWORD: error = EPERM; break; + case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break; + case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break; + case ERROR_INVALID_TARGET_HANDLE: error = EIO; break; + case ERROR_INVALID_WORKSTATION: error = EACCES; break; + case ERROR_IO_DEVICE: error = EIO; break; + case ERROR_IO_INCOMPLETE: error = EINTR; break; + case ERROR_LOCKED: error = EBUSY; break; + case ERROR_LOCK_VIOLATION: error = EACCES; break; + case ERROR_LOGON_FAILURE: error = EACCES; break; + case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break; + case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break; + case ERROR_MORE_DATA: error = EPIPE; break; + case ERROR_NEGATIVE_SEEK: error = ESPIPE; break; + case ERROR_NOACCESS: error = EFAULT; break; + case ERROR_NONE_MAPPED: error = EINVAL; break; + case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break; + case ERROR_NOT_READY: error = EAGAIN; break; + case ERROR_NOT_SAME_DEVICE: error = EXDEV; break; + case ERROR_NO_DATA: error = EPIPE; break; + case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break; + case ERROR_NO_PROC_SLOTS: error = EAGAIN; break; + case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break; + case ERROR_OPEN_FAILED: error = EIO; break; + case ERROR_OPEN_FILES: error = EBUSY; break; + case ERROR_OPERATION_ABORTED: error = EINTR; break; + case ERROR_OUTOFMEMORY: error = ENOMEM; break; + case ERROR_PASSWORD_EXPIRED: error = EACCES; break; + case ERROR_PATH_BUSY: error = EBUSY; break; + case ERROR_PATH_NOT_FOUND: error = ENOENT; break; + case ERROR_PIPE_BUSY: error = EBUSY; break; + case ERROR_PIPE_CONNECTED: error = EPIPE; break; + case ERROR_PIPE_LISTENING: error = EPIPE; break; + case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break; + case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break; + case ERROR_READ_FAULT: error = EIO; break; + case ERROR_SEEK: error = EIO; break; + case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break; + case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break; + case ERROR_SHARING_VIOLATION: error = EACCES; break; + case ERROR_STACK_OVERFLOW: error = ENOMEM; break; + case ERROR_SWAPERROR: error = ENOENT; break; + case ERROR_TOO_MANY_MODULES: error = EMFILE; break; + case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break; + case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break; + case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break; + case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break; + case ERROR_WRITE_FAULT: error = EIO; break; + case ERROR_WRITE_PROTECT: error = EROFS; break; + } + return error; +} + + +int link(const char *oldpath, const char *newpath) +{ + typedef BOOL (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES); + static T create_hard_link = NULL; + if (!create_hard_link) { + create_hard_link = (T) GetProcAddress( + GetModuleHandle("kernel32.dll"), "CreateHardLinkA"); + if (!create_hard_link) + create_hard_link = (T)-1; + } + if (create_hard_link == (T)-1) { + errno = ENOSYS; + return -1; + } + if (!create_hard_link(newpath, oldpath, NULL)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + return 0; +} diff --git a/compat/mingw.h b/compat/mingw.h index 4f275cb8e6..20c02c7494 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -67,8 +67,6 @@ static inline int readlink(const char *path, char *buf, size_t bufsiz) { errno = ENOSYS; return -1; } static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } -static inline int link(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) @@ -134,6 +132,7 @@ int getpagesize(void); /* defined in MinGW's libgcc.a */ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); +int link(const char *oldpath, const char *newpath); /* * replacements of existing functions From 5a31d04bc8b2387f11f1d0a95d9b36c25685e59e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Jan 2009 09:59:43 +0100 Subject: [PATCH 0500/3720] Windows: Fix intermittent failures of t7701 The last test case checks whether unpacked objects receive the time stamp of the pack file. Due to different implementations of stat(2) by MSYS and our version in compat/mingw.c, the test fails in about half of the test runs. Note the following facts: - The test uses perl's -M operator to compare the time stamps. Since we depend on MSYS perl, the result of this operator is based on MSYS's implementation of the stat(2) call. - NTFS on Windows records fractional seconds. - The MSYS implementation of stat(2) *rounds* fractional seconds to full seconds instead of truncating them. This becomes obvious by comparing the modification times reported by 'ls --full-time $f' and 'stat $f' for various files $f. - Our implementation of stat(2) in compat/mingw.c *truncates* to full seconds. The consequence of this is that - add_packed_git() picks up a truncated whole second modification time from the pack file time stamp, which is then used for the loose objects, while the pack file retains its time stamp in fractional seconds; - but the test case compares the pack file's rounded modification times to the loose objects' truncated modification times. And half of the time the rounded modification time is not the same as its truncated modification time. The fix is that we replace perl by 'test-chmtime -v +0', which prints the truncated whole-second mtime without modifying it. Signed-off-by: Johannes Sixt --- t/t7701-repack-unpack-unreachable.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index 63a8225ae5..5babdf26e6 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -50,12 +50,10 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' ' compare_mtimes () { - perl -e 'my $reference = shift; - foreach my $file (@ARGV) { - exit(1) unless(-f $file && -M $file == -M $reference); - } - exit(0); - ' -- "$@" + read tref rest && + while read t rest; do + test "$tref" = "$t" || break + done } test_expect_success '-A without -d option leaves unreachable objects packed' ' @@ -87,7 +85,9 @@ test_expect_success 'unpacked objects receive timestamp of pack file' ' tmppack=".git/objects/pack/tmp_pack" && ln "$packfile" "$tmppack" && git repack -A -l -d && - compare_mtimes "$tmppack" "$fsha1path" "$csha1path" "$tsha1path" + test-chmtime -v +0 "$tmppack" "$fsha1path" "$csha1path" "$tsha1path" \ + > mtimes && + compare_mtimes < mtimes ' test_done From db75811cfaec90fa8a114f46c84d408f5e6ca7c9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 5 Feb 2009 17:15:31 +0100 Subject: [PATCH 0501/3720] MinGW tests: override 'pwd', too With MinGW based Git, we must not use the POSIXified version of paths. So we need to use 'pwd -W' instead of 'pwd' without options. Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 3 --- t/test-lib.sh | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index b4dc0d2fbe..1f59960d90 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -107,9 +107,6 @@ test_expect_success 'remove remote' ' ) ' -case $(uname -s) in -*MINGW*) pwd() { builtin pwd -W; } ;; -esac cat > test/expect << EOF * remote origin URL: $(pwd)/one diff --git a/t/test-lib.sh b/t/test-lib.sh index cce3636c1b..7a5f77b765 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -536,5 +536,8 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + pwd() { + builtin pwd -W + } ;; esac From ea81ef5fea2fb40e665171ac30a3bfb3468e87b8 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 7 Feb 2009 00:03:47 +0100 Subject: [PATCH 0502/3720] builtin-receive-pack: Remove leftovers of old RUNTIME_PREFIX implementation --- builtin-receive-pack.c | 3 --- merge-index.c | 2 -- mktag.c | 2 -- 3 files changed, 7 deletions(-) diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index 8da9c1ff3a..6de186c397 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -607,9 +607,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) int i; char *dir = NULL; - if (argv[0] && *argv[0]) - git_extract_argv0_path(argv[0]); - argv++; for (i = 1; i < argc; i++) { const char *arg = *argv++; diff --git a/merge-index.c b/merge-index.c index 4c51b14eab..aa9cf23a39 100644 --- a/merge-index.c +++ b/merge-index.c @@ -96,8 +96,6 @@ int main(int argc, char **argv) git_extract_argv0_path(argv[0]); - git_extract_argv0_path(argv[0]); - setup_git_directory(); read_cache(); diff --git a/mktag.c b/mktag.c index 21370328e2..99a356e9ee 100644 --- a/mktag.c +++ b/mktag.c @@ -162,8 +162,6 @@ int main(int argc, char **argv) git_extract_argv0_path(argv[0]); - git_extract_argv0_path(argv[0]); - setup_git_directory(); if (strbuf_read(&buf, 0, 4096) < 0) { From 563478c3f83be93ab369368c5a418d7f75941594 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 9 Feb 2009 10:24:51 +0100 Subject: [PATCH 0503/3720] t2200: Avoid glob pattern that also matches files On Windows, there is an unfortunate interaction between the MSYS bash and git's command line processing: - Since Windows's CMD does not do the wildcard expansion, but passes arguments like path? through to the programs, the programs must do the expansion themselves. This happens in the startup code before main() is entered. - bash, however, passes the argument "path?" to git, assuming that git will see the unquoted word unchanged as a single argument. But actually git expands the unquoted word before main() is entered. Since at the time when the git ls-files is invoked not all names that the test case is interested in exist as files, only a subset was listed, so that the test failed. We now list all interesting paths explicitly. Signed-off-by: Johannes Sixt --- t/t2200-add-update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index b2ddf5ace3..652801ebca 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -150,7 +150,7 @@ test_expect_success 'add -u resolves unmerged paths' ' echo 2 >path3 && echo 2 >path5 && git add -u && - git ls-files -s "path?" >actual && + git ls-files -s path1 path3 path4 path5 path6 >actual && { echo "100644 $three 0 path1" echo "100644 $one 1 path3" From 861050cc2eaa963fcdb3b0860b854aee5f87e727 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 17 Feb 2009 18:54:01 +0100 Subject: [PATCH 0504/3720] t3400-rebase: Move detached HEAD check earlier 3ec7371f (Add two extra tests for git rebase, 2009-02-09) added a check that rebase works on a detached HEAD. For this check, the last test was picked, whose topic is to rebase a mode change. This rebase operation amounts to a no-op on Windows/MinGW so that HEAD@{1} *is* modechange@{1}, and the intended detached HEAD test fails. This patch moves the check earlier, into the group of tests that check basic rebase properties. Signed-off-by: Johannes Sixt --- t/t3400-rebase.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 8c0c5f5982..be7ae5a004 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -48,6 +48,10 @@ test_expect_success \ 'the rebase operation should not have destroyed author information' \ '! (git log | grep "Author:" | grep "<>")' +test_expect_success 'HEAD was detached during rebase' ' + test $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1}) +' + test_expect_success 'rebase after merge master' ' git reset --hard topic && git merge master && @@ -85,10 +89,6 @@ test_expect_success 'rebase a single mode change' ' GIT_TRACE=1 git rebase master ' -test_expect_success 'HEAD was detached during rebase' ' - test $(git rev-parse HEAD@{1}) != $(git rev-parse modechange@{1}) -' - test_expect_success 'Show verbose error when HEAD could not be detached' ' : > B && test_must_fail git rebase topic 2> output.err > output.out && From 89012a7916918de08031e7c415afd79d9e68dce2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2009 16:22:36 +0100 Subject: [PATCH 0505/3720] Remove last remnant of NOEXECTEMPL Upstream Git learnt the trick from us, but decided to call it 'sample' instead of 'noexec'. Signed-off-by: Johannes Schindelin --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index a9bbf3d8a3..be00623c81 100644 --- a/Makefile +++ b/Makefile @@ -809,7 +809,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - NOEXECTEMPL = .noexec htmldir=doc/git/html/ endif ifneq (,$(findstring arm,$(uname_M))) From eebdca3a654bfb95018514d5b5b8803c1fcd3343 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 19:51:54 +0100 Subject: [PATCH 0506/3720] Revert unnecessary quoting of SHELL_PATH In bf788d7(Makefile: be nice when running in a path containing spaces), the Makefile was changed so that the SHELL_PATH is quoted, but that is actually not necessary, as we still have POSIX paths at that point, and we use /bin/sh which has no space in it. Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index be00623c81..0b0628a98c 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ all:: # broken, or spawning external process is slower than built-in grep git has). GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE - @"$(SHELL_PATH)" ./GIT-VERSION-GEN + @$(SHELL_PATH) ./GIT-VERSION-GEN -include GIT-VERSION-FILE uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') From e673e45f5893fc969b58c81553832efd8cfd0435 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 19:54:24 +0100 Subject: [PATCH 0507/3720] MinGW: use POSIXy signature of waitpid() Git's source code expects waitpid() to return a signed int status. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index d6005ad545..6219e18843 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -109,7 +109,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +static inline int waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); From 6d3e71d428b1ee007339d679c26a336c8aefeade Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 19:56:41 +0100 Subject: [PATCH 0508/3720] MinGW: only override PRIuMAX for GCC older than version 4 GCC has no problems with PRIuMAX with recent GCC versions, but these versions do not like I64u any longer. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 6219e18843..8898006278 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -200,7 +200,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') #define PATH_SEP ';' +#if !defined(__GNUC__) || __GNUC__ < 3 #define PRIuMAX "I64u" +#endif void mingw_open_html(const char *path); #define open_html mingw_open_html From 85f2fd02bd2602e10415bf8aa4e085a9658e2d18 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:12:41 +0100 Subject: [PATCH 0509/3720] Makefile: move the last MinGW specific settings to the appropriate place If we ever hope to use plain upstream git.git in msysGit, we need to play nice with other platforms. So move the MinGW specific settings where they do not affect anybody else. Signed-off-by: Johannes Schindelin --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 0b0628a98c..68c2d846dd 100644 --- a/Makefile +++ b/Makefile @@ -191,7 +191,7 @@ STRIP ?= strip # runtime figures out where they are based on the path to the executable. # This can help installing the suite in a relocatable way. -prefix = +prefix = $(HOME) bindir_relative = bin bindir = $(prefix)/$(bindir_relative) mandir = share/man @@ -235,7 +235,7 @@ AR = ar RM = rm -f TAR = tar FIND = find -INSTALL = /bin/install +INSTALL = install RPMBUILD = rpmbuild TCL_PATH = tclsh TCLTK_PATH = wish @@ -592,7 +592,7 @@ BUILTIN_OBJS += builtin-verify-tag.o BUILTIN_OBJS += builtin-write-tree.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) -EXTLIBS = /mingw/lib/libz.a +EXTLIBS = # # Platform specific tweaks @@ -779,6 +779,9 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o endif ifneq (,$(findstring MINGW,$(uname_S))) + prefix = + INSTALL = /bin/install + EXTLIBS += /mingw/lib/libz.a NO_MMAP = YesPlease NO_PREAD = YesPlease NO_OPENSSL = YesPlease From 5461f4e7863a655a6f5792edc8dc9768a62948e7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:22:14 +0100 Subject: [PATCH 0510/3720] Undo MSys specific munging of ssh transport URLs We have our own msys-1.0.dll, which needs no more munging of the ssh transport URLs. Besides, almost everything related to remotes is builtin by now. Signed-off-by: Johannes Schindelin --- git-parse-remote.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) mode change 100644 => 100755 git-parse-remote.sh diff --git a/git-parse-remote.sh b/git-parse-remote.sh old mode 100644 new mode 100755 index 7c0d242eec..695a4094bb --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -51,8 +51,7 @@ get_remote_url () { ;; *) die "internal error: get-remote-url $1" ;; - esac | sed "s|^\(.[^:][^:]*\):\(/[^/]\)|ssh://\1\2|" - # work around MinGW path mangling + esac } get_default_remote () { From 8d785de3c205c870f6ce3e459c27e3f2b849b1a7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:25:13 +0100 Subject: [PATCH 0511/3720] gitk: remove workaround for missing msgfmt In the meantime, gitk's Makefile has learnt to detect the absence of msgfmt and use the drop-in replacement in Tcl (which was developed for msysGit, but has been adopted both by gitk and git-gui). Signed-off-by: Johannes Schindelin --- gitk-git/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gitk-git/Makefile b/gitk-git/Makefile index 2dda57cbae..e1b6045605 100644 --- a/gitk-git/Makefile +++ b/gitk-git/Makefile @@ -19,10 +19,6 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) ## po-file creation rules XGETTEXT ?= xgettext -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') -ifneq (,$(findstring MINGW,$(uname_S))) - NO_MSGFMT=1 -endif ifdef NO_MSGFMT MSGFMT ?= $(TCL_PATH) po/po2msg.sh else From 7cb52f1ebf546159e5460db087d9343d1b4139ed Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:28:26 +0100 Subject: [PATCH 0512/3720] No longer force use of /usr/bin/sort In msysGit, the PATH contains the MSys paths before anything else, so we can use "sort" (instead of "/usr/bin/sort"), just like git.git. Signed-off-by: Johannes Schindelin --- check-builtins.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-builtins.sh b/check-builtins.sh index cd09309838..d6fe6cf174 100755 --- a/check-builtins.sh +++ b/check-builtins.sh @@ -9,7 +9,7 @@ EOF } | make -f - sayIt 2>/dev/null | sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p' | -/usr/bin/sort | +sort | { bad=0 while read builtin From c09458c701353b8e0ad92fe2d0245636e17cb8b8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:29:49 +0100 Subject: [PATCH 0513/3720] Remove hopelessly obsolete README.MinGW Rather than letting it get even more stale, remove README.MinGW. Signed-off-by: Johannes Schindelin --- README.MinGW | 77 ---------------------------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 README.MinGW diff --git a/README.MinGW b/README.MinGW deleted file mode 100644 index 74eb104c2c..0000000000 --- a/README.MinGW +++ /dev/null @@ -1,77 +0,0 @@ -This is a port of GIT to Windows using MinGW. - -The goal of this port is to have the tools runnable from the Windows -command line, not from MinGW's rxvt+bash environment. - -(Note: This file was written after-the-fact and may contain errors. -If you are trying this, please make notes and update it.) - - -INSTALLATION ------------- - -In order to compile this code you need: - -- MSYS, e.g. MSYS-1.0.11-2004.04.30-1.exe -- MinGW, e.g. MinGW-5.0.2.exe -- mingwruntime, e.g. mingw-runtime-3.9.tar.gz -- compilers and tools: - binutils-2.15.91-20040904-1.tar.gz - gcc-core-3.4.2-20040916-1.tar.gz - gcc-g++-3.4.2-20040916-1.tar.gz - gdb-6.3-2.exe - mingw32-make-3.80.0-3.tar.gz - unzip-5.51-1-bin.zip (this is not from MinGW, iirc) - msysDTK-1.0.1.exe (contains ssh, perl) - bash-3.1-MSYS-1.0.11-snapshot.tar.bz2 -- additional libraries: - zlib-1.2.3-mingwPORT-1.tar - w32api-3.6.tar.gz - tcltk-8.4.1-1.exe (for gitk, git-gui) - libiconv-1.9.2-1-{lib,bin,lib}.zip (for git-am, - from http://gnuwin32.sourceforge.net/packages/libiconv.htm) - -I am using these settings in config.mak to have pointers to the right tools: - -TCL_PATH=tclsh84 -TCLTK_PATH=wish84 -SHELL_PATH=D:/MSYS/1.0/bin/sh -PERL_PATH=D:/MSYS/1.0/bin/perl - - -STATUS ------- - -This code base will not compile on a POSIX system, although any help -to introduce the necessary #ifdefs is welcome. As such the status quo -is in no way intended to be merged upstream. - -This works: - -- All the plumbings. -- Many porcelains, in particular, checkout, add, rm, commit, diff, - branch, merge, rebase, log, show, bisect, grep... -- pull, clone, fetch, push via native git protocal as well as ssh. -- Local pull, clone, fetch, push. -- gitk, if invoked as "wish84 \bin\gitk". Ditto for git-gui. - -This does not work: - -- daemon, svn, *import, cvs* -- and certainly a lot more that I never have found a need to look at. - -Caveats (aka bugs): - -- Internally, the ported tools must do their own command line quoting - when other plumbings are executed. This sort of quoting is currently - implemented *very* simplistic: It just watches out for whitespace - and double quote `"' characters. This may become a problem if you have - exotic characters in your file names. - -- It seems that MSYS's default bash, 2.05b, has a bug that breaks git-am - (and, hence, git-rebase). If you see this error: - - Patch is empty. Was is split wrong? - - you need bash 3.1: Just unpack bash-3.1*.tar.bz2 and copy its bash.exe - over $MSYS/bin/sh.exe. From 3cb35a31b04fb8e5cbfda3affcaa87dfee620355 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:32:47 +0100 Subject: [PATCH 0514/3720] MinGW: use off64_t and lseek64() On Windows, off_t is restricted to 32-bit, even if it is perfectly capable of using 64-bit offsets; Force the use of 64-bit offsets by overriding the declarations of off_t and lseek() with their 64-bit counterparts. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 8898006278..bfdfdb4940 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -117,6 +117,9 @@ static inline int waitpid(pid_t pid, int *status, unsigned options) return -1; } +#define off_t off64_t +#define lseek lseek64 + /* * implementations of missing functions */ From b824fc9cefb0317b98f6fc34c1192d409e859ea2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2009 15:32:55 +0100 Subject: [PATCH 0515/3720] Introduce the function strip_path_suffix() The function strip_path_suffix() will try to strip a given suffix from a given path. The suffix must start at a directory boundary (i.e. "core" is not a path suffix of "libexec/git-core", but "git-core" is). Arbitrary runs of directory separators ("slashes") are assumed identical. Example: prefix = strip_path_suffix("C:\\msysgit/\\libexec\\git-core", "libexec///git-core"); will set prefix to "C:\\msysgit". Signed-off-by: Johannes Schindelin --- cache.h | 1 + path.c | 32 ++++++++++++++++++++++++++++++++ t/t0060-path-utils.sh | 4 ++++ test-path-utils.c | 5 +++++ 4 files changed, 42 insertions(+) diff --git a/cache.h b/cache.h index 2d889deb26..362116dc74 100644 --- a/cache.h +++ b/cache.h @@ -629,6 +629,7 @@ const char *make_nonrelative_path(const char *path); const char *make_relative_path(const char *abs, const char *base); int normalize_absolute_path(char *buf, const char *path); int longest_ancestor_length(const char *path, const char *prefix_list); +char *strip_path_suffix(const char *path, const char *suffix); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/path.c b/path.c index 108d9e9599..719be21e75 100644 --- a/path.c +++ b/path.c @@ -457,3 +457,35 @@ int longest_ancestor_length(const char *path, const char *prefix_list) return max_len; } + +/* strip arbitrary amount of directory separators at end of path */ +static inline int chomp_trailing_dir_sep(const char *path, int len) +{ + while (len && is_dir_sep(path[len - 1])) + len--; + return len; +} + +/* sets prefix if the suffix matches */ +char *strip_path_suffix(const char *path, const char *suffix) +{ + int path_len = strlen(path), suffix_len = strlen(suffix); + + while (suffix_len) { + if (!path_len) + return NULL; + + if (is_dir_sep(path[path_len - 1])) { + if (!is_dir_sep(suffix[suffix_len - 1])) + return NULL; + path_len = chomp_trailing_dir_sep(path, path_len); + suffix_len = chomp_trailing_dir_sep(suffix, suffix_len); + } + else if (path[--path_len] != suffix[--suffix_len]) + return NULL; + } + + if (path_len && !is_dir_sep(path[path_len - 1])) + return NULL; + return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); +} diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 6e7501f352..1df1d8948a 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -84,4 +84,8 @@ ancestor /foo/bar :://foo/.:: 4 ancestor /foo/bar //foo/./::/bar 4 ancestor /foo/bar ::/bar -1 +test_expect_success 'strip_path_suffix' ' + test c:/msysgit = $(test-path-utils strip_path_suffix \ + c:/msysgit/libexec//git-core libexec/git-core) +' test_done diff --git a/test-path-utils.c b/test-path-utils.c index 2c0f5a37e8..003680dcda 100644 --- a/test-path-utils.c +++ b/test-path-utils.c @@ -22,5 +22,10 @@ int main(int argc, char **argv) printf("%d\n", len); } + if (argc == 4 && !strcmp(argv[1], "strip_path_suffix")) { + char *prefix = strip_path_suffix(argv[2], argv[3]); + printf("%s\n", prefix ? prefix : "(null)"); + } + return 0; } From 047f0f01f21824cc925102ad4e8e623c4806e0aa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2009 15:41:37 +0100 Subject: [PATCH 0516/3720] system_path(): simplify using strip_path_suffix(), and add suffix "git" At least for the author of this patch, the logic in system_path() was too hard to understand. Using the function strip_path_suffix() documents the idea of the code better. The real change is to add the suffix "git", so that a runtime prefix will be computed correctly even when the executable was called in /git/ as is the case in msysGit (Windows insists to search the current directory before the PATH when looking for an executable). Signed-off-by: Johannes Schindelin --- exec_cmd.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index f234066def..217c12577f 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -23,35 +23,10 @@ const char *system_path(const char *path) assert(argv0_path); assert(is_absolute_path(argv0_path)); - if (!prefix) { - const char *strip[] = { - GIT_EXEC_PATH, - BINDIR, - 0 - }; - const char **s; - - for (s = strip; *s; s++) { - const char *sargv = argv0_path + strlen(argv0_path); - const char *ss = *s + strlen(*s); - while (argv0_path < sargv && *s < ss - && (*sargv == *ss || - (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { - sargv--; - ss--; - } - if (*s == ss) { - struct strbuf d = STRBUF_INIT; - /* We also skip the trailing directory separator. */ - assert(sargv - argv0_path - 1 >= 0); - strbuf_add(&d, argv0_path, sargv - argv0_path - 1); - prefix = strbuf_detach(&d, NULL); - break; - } - } - } - - if (!prefix) { + if (!prefix && + !(prefix = strip_path_suffix(argv0_path, GIT_EXEC_PATH)) && + !(prefix = strip_path_suffix(argv0_path, BINDIR)) && + !(prefix = strip_path_suffix(argv0_path, "git"))) { prefix = PREFIX; fprintf(stderr, "RUNTIME_PREFIX requested, " "but prefix computation failed. " From fc8f39c0dad332a7c909d5a379eb01d594cf3594 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 19 Feb 2009 21:40:10 +0100 Subject: [PATCH 0517/3720] strip_path_suffix(): fix comment Signed-off-by: Johannes Schindelin --- path.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/path.c b/path.c index 719be21e75..b31d0e1fb1 100644 --- a/path.c +++ b/path.c @@ -466,7 +466,11 @@ static inline int chomp_trailing_dir_sep(const char *path, int len) return len; } -/* sets prefix if the suffix matches */ +/* + * If path ends with suffix (complete path components), returns the + * part before suffix (sans trailing directory separators). + * Otherwise returns NULL. + */ char *strip_path_suffix(const char *path, const char *suffix) { int path_len = strlen(path), suffix_len = strlen(suffix); From 96fd02ed68fb068ba75d980bcd280bbdb5169bba Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Mar 2009 19:15:02 +0100 Subject: [PATCH 0518/3720] Revert "MinGW: use off64_t and lseek64()" This reverts commit 3cb35a31b04fb8e5cbfda3affcaa87dfee620355. The fix was incorrect. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index bfdfdb4940..8898006278 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -117,9 +117,6 @@ static inline int waitpid(pid_t pid, int *status, unsigned options) return -1; } -#define off_t off64_t -#define lseek lseek64 - /* * implementations of missing functions */ From ff9031617a6b8e3f49d2362d91e34029dace5ce2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Mar 2009 18:46:54 +0100 Subject: [PATCH 0519/3720] Quiet make: do not leave Windows behind On Windows, we have to check whether there are scripts which would override .exe files, but this check missed the "quietification". Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 105c31f51d..3c54b629df 100644 --- a/Makefile +++ b/Makefile @@ -1139,7 +1139,7 @@ SHELL = $(SHELL_PATH) all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';) + $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';) endif all:: From f30905f5dd684e4ca57408f4e8f512d46791702f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Mar 2009 18:34:42 +0100 Subject: [PATCH 0520/3720] Add an (optional, since expensive) test for >2gb clones Define GIT_TEST_CLONE_2GB=t if you want the test not to be skipped. The test works by constructing a repository larger than 2gb, and then cloning it. The repository is forced larger than 2gb by setting compression and delta depth to zero, and then adding just enough unique objects of a given size. The objects consist of a running decimal number in ASCII, padded by spaces. Should that break in the future, e.g. when pack v4 becomes default, there is a commented-out call to test-genrandom which can be substituted, but that uses more cycles than the current method. Signed-off-by: Johannes Schindelin --- t/t5705-clone-2gb.sh | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 t/t5705-clone-2gb.sh diff --git a/t/t5705-clone-2gb.sh b/t/t5705-clone-2gb.sh new file mode 100755 index 0000000000..9f52154cac --- /dev/null +++ b/t/t5705-clone-2gb.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +test_description='Test cloning a repository larger than 2 gigabyte' +. ./test-lib.sh + +test -z "$GIT_TEST_CLONE_2GB" && +say "Skipping expensive 2GB clone test; enable it with GIT_TEST_CLONE_2GB=t" && +test_done && +exit + +test_expect_success 'setup' ' + + git config pack.compression 0 && + git config pack.depth 0 && + blobsize=$((20*1024*1024)) && + blobcount=$((2*1024*1024*1024/$blobsize+1)) && + i=1 && + (while test $i -le $blobcount + do + printf "Generating blob $i/$blobcount\r" >&2 && + printf "blob\nmark :$i\ndata $blobsize\n" && + #test-genrandom $i $blobsize && + printf "%-${blobsize}s" $i && + echo "M 100644 :$i $i" >> commit + i=$(($i+1)) || + echo $? > exit-status + done && + echo "commit refs/heads/master" && + echo "author A U Thor 123456789 +0000" && + echo "committer C O Mitter 123456789 +0000" && + echo "data 5" && + echo ">2gb" && + cat commit) | + git fast-import && + test ! -f exit-status + +' + +test_expect_success 'clone' ' + + git clone --bare --no-hardlinks . clone + +' + +test_done From 081c091d507cc2e7b8f318d9e999335d9e96caf8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Mar 2009 19:15:02 +0100 Subject: [PATCH 0521/3720] MinGW: 64-bit file offsets The type 'off_t' should be used everywhere so that the bit-depth of that type can be adjusted in the standard C library, and you just need to recompile your program to benefit from the extended precision. Only that it was not done that way in the MS runtime library. This patch reroutes off_t to off64_t and provides the other necessary changes so that finally, clones larger than 2 gigabyte work on Windows (provided you are on a file system that allows files larger than 2gb). Initial patch by Sickboy . Signed-off-by: Johannes Schindelin --- compat/mingw.c | 8 +++++--- compat/mingw.h | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 869bd4acbe..c011754023 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -46,7 +46,8 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_uid = 0; buf->st_nlink = 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_size = fdata.nFileSizeLow | + (((off_t)fdata.nFileSizeHigh)<<32); buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); @@ -101,7 +102,7 @@ int mingw_fstat(int fd, struct stat *buf) } /* direct non-file handles to MS's fstat() */ if (GetFileType(fh) != FILE_TYPE_DISK) - return fstat(fd, buf); + return _fstati64(fd, buf); if (GetFileInformationByHandle(fh, &fdata)) { buf->st_ino = 0; @@ -109,7 +110,8 @@ int mingw_fstat(int fd, struct stat *buf) buf->st_uid = 0; buf->st_nlink = 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_size = fdata.nFileSizeLow | + (((off_t)fdata.nFileSizeHigh)<<32); buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); diff --git a/compat/mingw.h b/compat/mingw.h index 8898006278..92fb3103c2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -162,11 +162,14 @@ int mingw_rename(const char*, const char*); /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. */ +#define off_t off64_t +#define stat _stati64 +#define lseek _lseeki64 int mingw_lstat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define stat(x,y) mingw_lstat(x,y) +#define stat64(x,y) mingw_lstat(x,y) int mingw_utime(const char *file_name, const struct utimbuf *times); #define utime mingw_utime From fc048d74273cbf98c412916dd3332d03bf334c79 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 15:19:39 +0100 Subject: [PATCH 0522/3720] Brown paper bag fix for MinGW 64-bit stat When overriding the identifier "stat" so that "struct stat" will be substituted with "struct _stati64" everywhere, I tried to fix the calls to the _function_ stat(), too, but I forgot to change the earlier attempt "stat64" to "_stati64" there. So, the stat() calls were overridden by calls to _stati64() instead. Unfortunately, there is a function _stati64() so that I missed that calls to stat() were not actually overridden by calls to mingw_lstat(), but t4200-rerere.sh showed the error. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 92fb3103c2..a0b74fb7ca 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -169,7 +169,7 @@ int mingw_lstat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define stat64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_lstat(x,y) int mingw_utime(const char *file_name, const struct utimbuf *times); #define utime mingw_utime From dba002b9e521c639847650fbaeb8b87b66b9562e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 16:36:09 +0100 Subject: [PATCH 0523/3720] MinGW: fix diff --no-index /dev/null ... When launching "diff --no-index" with a parameter "/dev/null", the MSys bash converts the "/dev/null" to a "nul", which usually makes sense. But diff --no-index got confused and tried to access a _file_ called "nul". While at it, the comment in t4012, expressed as ":# " was turned into ": " so that MSys' path name mangling does not kick in. With this patch, t4012 passes in msysGit. Signed-off-by: Johannes Schindelin --- diff-no-index.c | 4 ++++ t/t4012-diff-binary.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/diff-no-index.c b/diff-no-index.c index 0a14268ba9..598687b50a 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -38,6 +38,10 @@ static int get_mode(const char *path, int *mode) if (!path || !strcmp(path, "/dev/null")) *mode = 0; +#ifdef _WIN32 + else if (!strcasecmp(path, "nul")) + *mode = 0; +#endif else if (!strcmp(path, "-")) *mode = create_ce_mode(0666); else if (lstat(path, &st)) diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index 3cf5b5c4ea..f64aa48d24 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -87,7 +87,7 @@ nul_to_q() { test_expect_success 'diff --no-index with binary creation' ' echo Q | q_to_nul >binary && - (:# hide error code from diff, which just indicates differences + (: hide error code from diff, which just indicates differences git diff --binary --no-index /dev/null binary >current || true ) && From 23c5477dfb63cee46806b9f9c8d9d73d93db776e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 17:40:15 +0100 Subject: [PATCH 0524/3720] t4129: skip tests if core.filemode = false If we cannot test file modes, we cannot test file modes. Signed-off-by: Johannes Schindelin --- t/t4129-apply-samemode.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index adfcbb5a3b..a74101abba 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -16,6 +16,11 @@ test_expect_success setup ' git diff --stat -p >patch-1.txt ' +test "$(git config --bool core.filemode)" = false && +say "executable bit not honored - skipping" && +test_done && +exit + test_expect_success 'same mode (no index)' ' git reset --hard && chmod +x file && From 3a76fdaf98efbb1dc2f71352c811ab6d2710b74f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 19:12:37 +0100 Subject: [PATCH 0525/3720] MinGW: GCC >= 4 does not need SNPRINTF_SIZE_CORR anymore Signed-off-by: Johannes Schindelin --- Makefile | 1 - compat/snprintf.c | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3c54b629df..801303ebc8 100644 --- a/Makefile +++ b/Makefile @@ -804,7 +804,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch - COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 diff --git a/compat/snprintf.c b/compat/snprintf.c index 357e733074..7d780508a7 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -6,8 +6,12 @@ * number of characters to write without the trailing NUL. */ #ifndef SNPRINTF_SIZE_CORR +#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 3 +#define SNPRINTF_SIZE_CORR 1 +#else #define SNPRINTF_SIZE_CORR 0 #endif +#endif #undef vsnprintf int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) From 3d27683b91df7d4fd6b70e32ed12b08721a46dbd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 19:44:03 +0100 Subject: [PATCH 0526/3720] Revert "MinGW: only override PRIuMAX for GCC older than version 4" This reverts commit 6d3e71d428b1ee007339d679c26a336c8aefeade. Apparently, GCC >= 4 does not like %I64u as modifier to show unsigned long longs. However, using %llu -- even if the compiler warning goes away -- fails spectacularly: The C runtime insists that %llu takes 32-bit numbers. So for now, we _have_ to live with compiler warnings galore. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index a0b74fb7ca..b82903c74a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -203,9 +203,7 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') #define PATH_SEP ';' -#if !defined(__GNUC__) || __GNUC__ < 3 #define PRIuMAX "I64u" -#endif void mingw_open_html(const char *path); #define open_html mingw_open_html From 04f4f675ae629eccb30be521868d9c1698d56170 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 20:29:54 +0100 Subject: [PATCH 0527/3720] MinGW: t6200 needs to understand Windows paths Signed-off-by: Johannes Schindelin --- t/t6200-fmt-merge-msg.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 8f5a06f7dd..763c46038a 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -82,6 +82,7 @@ test_expect_success 'merge-msg test #1' ' test_cmp expected actual ' +TEST_DIRECTORY=$(cd "$TEST_DIRECTORY" && pwd) cat >expected < Date: Sat, 7 Mar 2009 20:48:08 +0100 Subject: [PATCH 0528/3720] MinGW: the path separator to split GITPERLLIB is ';' on Win32 Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 801303ebc8..995a11c9f7 100644 --- a/Makefile +++ b/Makefile @@ -209,6 +209,7 @@ ETC_GITCONFIG = etc/gitconfig endif lib = lib # DESTDIR= +pathsep = : # default configuration for gitweb GITWEB_CONFIG = gitweb_config.perl @@ -776,6 +777,7 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o endif ifneq (,$(findstring MINGW,$(uname_S))) + pathsep = ; prefix = INSTALL = /bin/install EXTLIBS += /mingw/lib/libz.a @@ -1204,7 +1206,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl sed -e '1{' \ -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \ -e ' h' \ - -e ' s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ + -e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ -e ' H' \ -e ' x' \ -e '}' \ From d7bc3dd8f7a2091e9d7dec69bed96d53653d9a79 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 23:12:43 +0100 Subject: [PATCH 0529/3720] t5520: do not skip test that does not fail anymore Signed-off-by: Johannes Schindelin --- t/t5520-pull.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 8377733f7b..725771fac1 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -88,7 +88,6 @@ test_expect_success 'branch.to-rebase.rebase' ' test new = $(git show HEAD:file2) ' -say "Remote does not work in t/ - skipping." || test_expect_success '--rebase with rebased upstream' ' git remote add -f me . && From b1744a5fde45def23aa5778bf4a22df8f070422d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Mar 2009 17:58:32 +0100 Subject: [PATCH 0530/3720] t7300: fix clean up on Windows On Windows, you cannot remove files that are in use, not even with 'rm -rf'. So we need to run 'exec --- t/t7300-clean.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 1636fac2a4..929d5d4d3b 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -373,9 +373,9 @@ test_expect_success 'removal failure' ' mkdir foo && touch foo/bar && - exec Date: Wed, 18 Mar 2009 09:43:24 +0100 Subject: [PATCH 0531/3720] Let t0000 pass on Windows again This is needed after the recent test_cmp conversion (188c3827). Signed-off-by: Johannes Sixt --- t/t0000-basic.sh | 64 +++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 5749602673..f7cdbad7cb 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -30,22 +30,6 @@ fi . ./test-lib.sh -test "$no_symlinks" && { - DIFF=$(which diff) - - function diff () { - opt= - case "$1" in -*) opt=$1; shift;; esac - tr -d "\015" < $1 > $1.doof - grep -v "^:\?120000" < $2 | \ - sed -e s/58a09c23e2ca152193f2786e06986b7b6712bdbe/600f42758e4458c37c2c1f8063378f540b4efad7/ \ - -e s/21ae8269cacbe57ae09138dcc3a2887f904d02b3/cfb8591b2f65de8b8cc1020cd7d9e67e7793b325/ \ - -e s/3c5e5399f3a333eddecce7a9b9465b63f65f51e2/ce580448f0148b985a513b693fdf7d802cacb44f/ \ - > $2.doof - $DIFF $opt $1.doof $2.doof - } -} - ################################################################ # git init has been done in an empty repository. # make sure it is empty. @@ -116,12 +100,31 @@ test_expect_success \ 'test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904' # Various types of objects +# Some filesystems do not support symblic links; on such systems +# some expected values are different mkdir path2 path3 path3/subp3 -for p in path0 path2/file2 path3/file3 path3/subp3/file3 +paths='path0 path2/file2 path3/file3 path3/subp3/file3' +for p in $paths do echo "hello $p" >$p - ln -s "hello $p" ${p}sym done +if test -z "$no_symlinks" +then + for p in $paths + do + ln -s "hello $p" ${p}sym + done + expectfilter=cat + expectedtree=087704a96baf1c2d1c869a8b084481e121c88b5b + expectedptree1=21ae8269cacbe57ae09138dcc3a2887f904d02b3 + expectedptree2=3c5e5399f3a333eddecce7a9b9465b63f65f51e2 +else + expectfilter='grep -v sym' + expectedtree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46 + expectedptree1=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325 + expectedptree2=ce580448f0148b985a513b693fdf7d802cacb44f +fi + test_expect_success \ 'adding various types of objects with git update-index --add.' \ 'find path* ! -type d -print | xargs git update-index --add' @@ -131,7 +134,7 @@ test_expect_success \ 'showing stage with git ls-files --stage' \ 'git ls-files --stage >current' -cat >expected <<\EOF +$expectfilter >expected <<\EOF 100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 @@ -149,11 +152,9 @@ test_expect_success \ test_expect_success \ 'writing tree out with git write-tree.' \ 'tree=$(git write-tree)' -expected_tree=087704a96baf1c2d1c869a8b084481e121c88b5b -test "$no_symlinks" && expected_tree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46 test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$tree" = "$expected_tree"' + 'test "$tree" = "$expectedtree"' test_expect_success \ 'showing tree with git ls-tree' \ @@ -164,6 +165,7 @@ cat >expected <<\EOF 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 EOF +test -z "$no_symlinks" && test_expect_success \ 'git ls-tree output for a known tree.' \ 'test_cmp expected current' @@ -173,7 +175,7 @@ test_expect_success \ test_expect_success \ 'showing tree with git ls-tree -r' \ 'git ls-tree -r $tree >current' -cat >expected <<\EOF +$expectfilter >expected <<\EOF 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 @@ -204,6 +206,7 @@ cat >expected <<\EOF 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym EOF +test -z "$no_symlinks" && test_expect_success \ 'git ls-tree -r output for a known tree.' \ 'test_cmp expected current' @@ -211,20 +214,16 @@ test_expect_success \ test_expect_success \ 'writing partial tree out with git write-tree --prefix.' \ 'ptree=$(git write-tree --prefix=path3)' -expected_tree=21ae8269cacbe57ae09138dcc3a2887f904d02b3 -test "$no_symlinks" && expected_tree=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325 test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = "$expected_tree"' + 'test "$ptree" = "$expectedptree1"' test_expect_success \ 'writing partial tree out with git write-tree --prefix.' \ 'ptree=$(git write-tree --prefix=path3/subp3)' -expect_tree=3c5e5399f3a333eddecce7a9b9465b63f65f51e2 -test "$no_symlinks" && expect_tree=ce580448f0148b985a513b693fdf7d802cacb44f test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = "$expect_tree"' + 'test "$ptree" = "$expectedptree2"' cat >badobjects <expected <<\EOF +$expectfilter >expected <<\EOF :100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0 :120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym :100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2 @@ -280,8 +279,7 @@ test_expect_success \ 'git diff-files >current && cmp -s current /dev/null' ################################################################ -P=087704a96baf1c2d1c869a8b084481e121c88b5b -test "$no_symlinks" && P=7bb943559a305bdd6bdee2cef6e5df2413c3d30a +P=$expectedtree test_expect_success \ 'git commit-tree records the correct tree in a commit.' \ 'commit0=$(echo NO | git commit-tree $P) && @@ -317,7 +315,7 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' -test "$no_symlinks" || +test -z "$no_symlinks" && test_expect_success 'absolute path works as expected' ' mkdir first && ln -s ../.git first/.git && From bf09f21ae48c0daec7ea17573465aea800b13a8f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 22 Jan 2009 11:25:07 +0100 Subject: [PATCH 0532/3720] t4129: cannot test executable mode on Windows Signed-off-by: Johannes Sixt --- t/t4129-apply-samemode.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index adfcbb5a3b..6284b80e3a 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -4,6 +4,9 @@ test_description='applying patch with mode bits' . ./test-lib.sh +say "executable mode not supported - skipping tests" +test_done + test_expect_success setup ' echo original >file && git add file && From 278924204288aa622d1ab319eaee08d8972d2d2b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 18 Mar 2009 13:31:38 +0100 Subject: [PATCH 0533/3720] t6031-merge-recursive: More fixes for exec bit challenged filesystems Commit 28f880241782024ecb212f1641c8dc487124523b improved the tests to work on filesystems that do not honor the exec bit, but it didn't go the full nine yards: If chmod +x does not work, then test -x will not work reliably, either, which was the only way how the tests checked the result. This patch works around the issue by testing the index if the filesystem does not report that the exec bit is set. Signed-off-by: Johannes Sixt --- t/t6031-merge-recursive.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index 8073e0c3ef..02aafa6d56 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -20,7 +20,7 @@ test_expect_success 'mode change in one branch: keep changed version' ' git commit -m b1 && git checkout a1 && git merge-recursive master -- a1 b1 && - test -x file1 + { test -x file1 || git ls-files -s file1 | grep ^100755; } ' test_expect_success 'mode change in both branches: expect conflict' ' @@ -46,7 +46,7 @@ test_expect_success 'mode change in both branches: expect conflict' ' echo "100644 $H 3 file2" ) >expect && test_cmp actual expect && - test -x file2 + { test -x file2 || git ls-files -s file2 | grep ^100755; } ' test_done From f659ae81d868ad7fbde7558187658cb965976a8c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 18 Mar 2009 13:35:40 +0100 Subject: [PATCH 0534/3720] test-lib: Work around missing sum on Windows Signed-off-by: Johannes Sixt --- t/t1002-read-tree-m-u-2way.sh | 6 ------ t/test-lib.sh | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index c4565d559d..5e40cec530 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -10,12 +10,6 @@ This is identical to t1001, but uses -u to update the work tree as well. ' . ./test-lib.sh -sum ./test-lib.sh >/dev/null 2>&1 || { - function sum () { - md5sum "$@" - } -} - _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { diff --git a/t/test-lib.sh b/t/test-lib.sh index 54556cf093..1be09a4754 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -646,5 +646,8 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + sum () { + md5sum "$@" + } ;; esac From b948d7cf5546d3ebb17d142ecee6fbd983c4b1e7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Mar 2009 17:58:32 +0100 Subject: [PATCH 0535/3720] t7300: fix clean up on Windows On Windows, you cannot remove files that are in use, not even with 'rm -rf'. So we need to run 'exec Signed-off-by: Johannes Sixt --- t/t7300-clean.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 1636fac2a4..929d5d4d3b 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -373,9 +373,9 @@ test_expect_success 'removal failure' ' mkdir foo && touch foo/bar && - exec Date: Wed, 18 Mar 2009 13:44:42 +0100 Subject: [PATCH 0536/3720] t0060: Fix tests on Windows Since the MSYS bash mangles absolute paths that it passes as command line arguments to non-MSYS progams (such as git or test-path-utils), we have to bend over backwards to squeeze some usefulness out of the existing tests. In particular, a set of path normalization tests is added that test relative paths. Some paths in the ancestor path tests are adjusted to help MSYS bash's path mangling heuristics. Signed-off-by: Johannes Sixt --- t/t0060-path-utils.sh | 116 ++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 33 deletions(-) diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 8336114f98..d849868e49 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -7,41 +7,91 @@ test_description='Test various path utilities' . ./test-lib.sh -norm_abs() { - test_expect_success "normalize absolute: $1 => $2" \ +norm_path() { + test_expect_success "normalize path: $1 => $2" \ "test \"\$(test-path-utils normalize_path_copy '$1')\" = '$2'" } +# On Windows, we are using MSYS's bash, which mangles the paths. +# Absolute paths are anchored at the MSYS installation directory, +# which means that the path / accounts for this many characters: +rootoff=$(test-path-utils normalize_path_copy / | wc -c) +# Account for the trailing LF: +if test "$rootoff" = 2; then + rootoff= # we are on Unix +else + rootoff=$(($rootoff-1)) +fi + ancestor() { - test_expect_success "longest ancestor: $1 $2 => $3" \ - "test \"\$(test-path-utils longest_ancestor_length '$1' '$2')\" = '$3'" + # We do some math with the expected ancestor length. + expected=$3 + if test -n "$rootoff" && test "x$expected" != x-1; then + expected=$(($expected+$rootoff)) + fi + test_expect_success "longest ancestor: $1 $2 => $expected" \ + "actual=\$(test-path-utils longest_ancestor_length '$1' '$2') && + test \"\$actual\" = '$expected'" } -norm_abs "" "" -norm_abs / / -norm_abs // / -norm_abs /// / -norm_abs /. / -norm_abs /./ / -norm_abs /./.. ++failed++ -norm_abs /../. ++failed++ -norm_abs /./../.// ++failed++ -norm_abs /dir/.. / -norm_abs /dir/sub/../.. / -norm_abs /dir/sub/../../.. ++failed++ -norm_abs /dir /dir -norm_abs /dir// /dir/ -norm_abs /./dir /dir -norm_abs /dir/. /dir/ -norm_abs /dir///./ /dir/ -norm_abs /dir//sub/.. /dir/ -norm_abs /dir/sub/../ /dir/ -norm_abs //dir/sub/../. /dir/ -norm_abs /dir/s1/../s2/ /dir/s2/ -norm_abs /d1/s1///s2/..//../s3/ /d1/s3/ -norm_abs /d1/s1//../s2/../../d2 /d2 -norm_abs /d1/.../d2 /d1/.../d2 -norm_abs /d1/..././../d2 /d1/d2 +norm_path "" "" +norm_path . "" +norm_path ./ "" +norm_path ./. "" +norm_path ./.. ++failed++ +norm_path ../. ++failed++ +norm_path ./../.// ++failed++ +norm_path dir/.. "" +norm_path dir/sub/../.. "" +norm_path dir/sub/../../.. ++failed++ +norm_path dir dir +norm_path dir// dir/ +norm_path ./dir dir +norm_path dir/. dir/ +norm_path dir///./ dir/ +norm_path dir//sub/.. dir/ +norm_path dir/sub/../ dir/ +norm_path dir/sub/../. dir/ +norm_path dir/s1/../s2/ dir/s2/ +norm_path d1/s1///s2/..//../s3/ d1/s3/ +norm_path d1/s1//../s2/../../d2 d2 +norm_path d1/.../d2 d1/.../d2 +norm_path d1/..././../d2 d1/d2 + +# Absolute path tests must be skipped on Windows because due to path mangling +# the test program never sees a POSIX-style absolute path +case $(uname -s) in +*MINGW*) + ;; +*) + +norm_path / / POSIX +norm_path // / POSIX +norm_path /// / POSIX +norm_path /. / POSIX +norm_path /./ / POSIX +norm_path /./.. ++failed++ POSIX +norm_path /../. ++failed++ POSIX +norm_path /./../.// ++failed++ POSIX +norm_path /dir/.. / POSIX +norm_path /dir/sub/../.. / POSIX +norm_path /dir/sub/../../.. ++failed++ POSIX +norm_path /dir /dir POSIX +norm_path /dir// /dir/ POSIX +norm_path /./dir /dir POSIX +norm_path /dir/. /dir/ POSIX +norm_path /dir///./ /dir/ POSIX +norm_path /dir//sub/.. /dir/ POSIX +norm_path /dir/sub/../ /dir/ POSIX +norm_path //dir/sub/../. /dir/ POSIX +norm_path /dir/s1/../s2/ /dir/s2/ POSIX +norm_path /d1/s1///s2/..//../s3/ /d1/s3/ POSIX +norm_path /d1/s1//../s2/../../d2 /d2 POSIX +norm_path /d1/.../d2 /d1/.../d2 POSIX +norm_path /d1/..././../d2 /d1/d2 POSIX + + ;; +esac ancestor / "" -1 ancestor / / -1 @@ -80,10 +130,10 @@ ancestor /foo/bar /:/foo:/bar/ 4 ancestor /foo/bar /foo:/:/bar/ 4 ancestor /foo/bar /:/bar/:/fo 0 ancestor /foo/bar /:/bar/ 0 -ancestor /foo/bar :://foo/. 4 -ancestor /foo/bar :://foo/.:: 4 -ancestor /foo/bar //foo/./::/bar 4 -ancestor /foo/bar ::/bar -1 +ancestor /foo/bar .:/foo/. 4 +ancestor /foo/bar .:/foo/.:.: 4 +ancestor /foo/bar /foo/./:.:/bar 4 +ancestor /foo/bar .:/bar -1 test_expect_success 'strip_path_suffix' ' test c:/msysgit = $(test-path-utils strip_path_suffix \ From ca0d369b00cad920e62b846f0ed4a9c8c5cf7114 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 13 Mar 2009 23:35:24 +0100 Subject: [PATCH 0537/3720] Tests on Windows: $(pwd) must return Windows-style paths Many tests pass $(pwd) in some form to git and later test that the output of git contains the correct value of $(pwd). For example, the test of 'git remote show' sets up a remote that contains $(pwd) and then the expected result must contain $(pwd). Again, MSYS-bash's path mangling kicks in: Plain $(pwd) uses the MSYS style absolute path /c/path/to/git. The test case would write this name into the 'expect' file. But when git is invoked, MSYS-bash converts this name to the Windows style path c:/path/to/git, and git would produce this form in the result; the test would fail. We fix this by passing -W to MSYS bash's pwd, which produces the Windows-style path. There are a two cases that need an accompanying change: - In t1504 the value of $(pwd) becomes part of a path list. In this case, the lone 'c' in something like /foo:c:/path/to/git:/bar inhibits MSYS-bashes path mangling; IOW in this case we want the /c/path/to/git form to allow path mangling. We use $PWD instead of $(pwd), which always has the latter form. - In t6200, $(pwd) - the Windows style path - must be used to construct the expected result because that is the path form that git sees. (The change in the test itself is just for consistency: 'git fetch' always sees the Windows-style path, with or without the change.) Signed-off-by: Johannes Sixt --- t/t1504-ceiling-dirs.sh | 2 +- t/t6200-fmt-merge-msg.sh | 4 ++-- t/test-lib.sh | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh index e377d48902..df5ad8c686 100755 --- a/t/t1504-ceiling-dirs.sh +++ b/t/t1504-ceiling-dirs.sh @@ -13,7 +13,7 @@ test_fail() { "git rev-parse --show-prefix" } -TRASH_ROOT="$(pwd)" +TRASH_ROOT="$PWD" ROOT_PARENT=$(dirname "$TRASH_ROOT") diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 8f5a06f7dd..2049ab6cf8 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -83,13 +83,13 @@ test_expect_success 'merge-msg test #1' ' ' cat >expected <actual && test_cmp expected actual diff --git a/t/test-lib.sh b/t/test-lib.sh index 1be09a4754..f4325f1b14 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -649,5 +649,9 @@ case $(uname -s) in sum () { md5sum "$@" } + # git sees Windows-style pwd + pwd () { + builtin pwd -W + } ;; esac From c43fb7fe2367a1b3a8ba76cf66212aa517a46e2d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 12 Mar 2009 15:25:10 +0100 Subject: [PATCH 0538/3720] MinGW: fix signature of CreateHardLinkA() If the declaration of CreateHardLinkA() does not contain the magic word "WINAPI", the stack will be clobbered in the error case. This fixes msysGit issue 204. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index c011754023..71e12dd478 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1122,7 +1122,7 @@ static int err_win_to_posix(DWORD winerr) int link(const char *oldpath, const char *newpath) { - typedef BOOL (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES); + typedef BOOL WINAPI (*T)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES); static T create_hard_link = NULL; if (!create_hard_link) { create_hard_link = (T) GetProcAddress( From 7e5a4c563667d011c0655679be3190461884a78e Mon Sep 17 00:00:00 2001 From: Janos Laube Date: Sat, 7 Mar 2009 03:54:10 +0100 Subject: [PATCH 0539/3720] support for win32 mmap Add USE_WIN32_MMAP which triggers the use of windows' native file memory mapping functionality in git_mmap()/git_munmap() functions. As git functions currently use mmap with MAP_PRIVATE set only, this implementation supports only that mode for now. On Windows offsets for memory mapped files need to match the allocation granularity. Take this into account when calculating the packed git- windowsize and file offsets. At the moment the only function which makes use of offsets in conjunction with mmap is use_pack() in sha1-file.c. Git fast-import's code path tries to map a portion of the temporary packfile which exceeds the current filesize, i.e. offset+length is greater than the filesize. The NO_MMAP code worked with that since pread() just reads the filecontent until EOF and returns gracefully, while MapViewOfFile() aborts the mapping and returns 'Access Denied'. Working around that by determining the filesize and adjusting the length parameter. Signed-off-by: Janos Laube --- Makefile | 6 +++++- compat/mingw.h | 5 +++++ compat/win32mmap.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 12 ++++++++--- 4 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 compat/win32mmap.c diff --git a/Makefile b/Makefile index 4097892986..4ac0e99906 100644 --- a/Makefile +++ b/Makefile @@ -781,7 +781,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) prefix = INSTALL = /bin/install EXTLIBS += /mingw/lib/libz.a - NO_MMAP = YesPlease NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_SYMLINK_HEAD = YesPlease @@ -805,6 +804,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease + USE_WIN32_MMAP = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o @@ -974,6 +974,10 @@ ifdef NO_MMAP COMPAT_CFLAGS += -DNO_MMAP COMPAT_OBJS += compat/mmap.o endif +ifdef USE_WIN32_MMAP + COMPAT_CFLAGS += -DUSE_WIN32_MMAP + COMPAT_OBJS += compat/win32mmap.o +endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD COMPAT_OBJS += compat/pread.o diff --git a/compat/mingw.h b/compat/mingw.h index b82903c74a..b1156b865e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -159,6 +159,11 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); int mingw_rename(const char*, const char*); #define rename mingw_rename +#ifdef USE_WIN32_MMAP +int mingw_getpagesize(void); +#define getpagesize mingw_getpagesize +#endif + /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. */ diff --git a/compat/win32mmap.c b/compat/win32mmap.c new file mode 100644 index 0000000000..66314b8430 --- /dev/null +++ b/compat/win32mmap.c @@ -0,0 +1,53 @@ +#include "../git-compat-util.h" + +/* Note that this doesn't return the actual pagesize, but + * the allocation granularity. If future Windows specific git code + * needs the real getpagesize function, we need to find another solution. + */ +int mingw_getpagesize(void) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwAllocationGranularity; +} + +void *git_mmap +(void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + HANDLE hmap; + void *temp; + size_t len; + struct stat st; + uint64_t o = offset; + uint32_t l = o & 0xFFFFFFFF; + uint32_t h = (o >> 32) & 0xFFFFFFFF; + + if (!fstat(fd, &st)) + len = xsize_t(st.st_size); + else + die("mmap: could not determine filesize"); + + if ((length + offset) > len) + length = len - offset; + + if (!(flags & MAP_PRIVATE)) + die("Invalid usage of mmap when built with USE_WIN32_MMAP"); + + hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_WRITECOPY, + 0, 0, 0); + + if (!hmap) + return MAP_FAILED; + + temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start); + + if (!CloseHandle(hmap)) + warning("unable to close file mapping handle\n"); + + return temp ? temp : MAP_FAILED; +} + +int git_munmap(void *start, size_t length) +{ + return !UnmapViewOfFile(start); +} diff --git a/git-compat-util.h b/git-compat-util.h index 878d83dd08..1eef4eb5b9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -166,7 +166,7 @@ static inline const char *skip_prefix(const char *str, const char *prefix) return strncmp(str, prefix, len) ? NULL : str + len; } -#ifdef NO_MMAP +#if defined(NO_MMAP) || defined(USE_WIN32_MMAP) #ifndef PROT_READ #define PROT_READ 1 @@ -180,13 +180,19 @@ static inline const char *skip_prefix(const char *str, const char *prefix) extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); extern int git_munmap(void *start, size_t length); +#else /* NO_MMAP || USE_WIN32_MMAP */ + +#include + +#endif /* NO_MMAP || USE_WIN32_MMAP */ + +#ifdef NO_MMAP + /* This value must be multiple of (pagesize * 2) */ #define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024) #else /* NO_MMAP */ -#include - /* This value must be multiple of (pagesize * 2) */ #define DEFAULT_PACKED_GIT_WINDOW_SIZE \ (sizeof(void*) >= 8 \ From 8593d8429cbd09ce813c8f42f5c00bb7d5cf9e7e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 10 Mar 2009 22:54:17 +0100 Subject: [PATCH 0540/3720] recv_sideband: Bands #2 and #3 always go to stderr This removes the last parameter of recv_sideband, by which the callers told which channel bands #2 and #3 should be written to. Sayeth Shawn Pearce: The definition of the streams in the current sideband protocol are rather well defined for the one protocol that uses it, fetch-pack/receive-pack: stream #1: pack data stream #2: stderr messages, progress, meant for tty stream #3: abort message, remote is dead, goodbye! Since both callers of the function passed 2 for the parameter, we hereby remove it and send bands #2 and #3 to stderr explicitly using fprintf. This has the nice side-effect that these two streams pass through our ANSI emulation layer on Windows. Signed-off-by: Johannes Sixt Acked-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- builtin-archive.c | 2 +- builtin-fetch-pack.c | 2 +- sideband.c | 19 ++++++++----------- sideband.h | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/builtin-archive.c b/builtin-archive.c index 60adef9363..ab50cebba0 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -52,7 +52,7 @@ static int run_remote_archiver(int argc, const char **argv, die("git archive: expected a flush"); /* Now, start reading from fd[0] and spit it out to stdout */ - rv = recv_sideband("archive", fd[0], 1, 2); + rv = recv_sideband("archive", fd[0], 1); close(fd[0]); close(fd[1]); rv |= finish_connect(conn); diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index c2e5adc884..2b360994bf 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -482,7 +482,7 @@ static int sideband_demux(int fd, void *data) { int *xd = data; - return recv_sideband("fetch-pack", xd[0], fd, 2); + return recv_sideband("fetch-pack", xd[0], fd); } static int get_pack(int xd[2], char **pack_lockfile) diff --git a/sideband.c b/sideband.c index cca3360546..899b1ff366 100644 --- a/sideband.c +++ b/sideband.c @@ -19,7 +19,7 @@ #define FIX_SIZE 10 /* large enough for any of the above */ -int recv_sideband(const char *me, int in_stream, int out, int err) +int recv_sideband(const char *me, int in_stream, int out) { unsigned pf = strlen(PREFIX); unsigned sf; @@ -41,8 +41,7 @@ int recv_sideband(const char *me, int in_stream, int out, int err) if (len == 0) break; if (len < 1) { - len = sprintf(buf, "%s: protocol error: no band designator\n", me); - safe_write(err, buf, len); + fprintf(stderr, "%s: protocol error: no band designator\n", me); return SIDEBAND_PROTOCOL_ERROR; } band = buf[pf] & 0xff; @@ -50,8 +49,8 @@ int recv_sideband(const char *me, int in_stream, int out, int err) switch (band) { case 3: buf[pf] = ' '; - buf[pf+1+len] = '\n'; - safe_write(err, buf, pf+1+len+1); + buf[pf+1+len] = '\0'; + fprintf(stderr, "%s\n", buf); return SIDEBAND_REMOTE_ERROR; case 2: buf[pf] = ' '; @@ -95,12 +94,12 @@ int recv_sideband(const char *me, int in_stream, int out, int err) memcpy(save, b + brk, sf); b[brk + sf - 1] = b[brk - 1]; memcpy(b + brk - 1, suffix, sf); - safe_write(err, b, brk + sf); + fprintf(stderr, "%.*s", brk + sf, b); memcpy(b + brk, save, sf); len -= brk; } else { int l = brk ? brk : len; - safe_write(err, b, l); + fprintf(stderr, "%.*s", l, b); len -= l; } @@ -112,10 +111,8 @@ int recv_sideband(const char *me, int in_stream, int out, int err) safe_write(out, buf + pf+1, len); continue; default: - len = sprintf(buf, - "%s: protocol error: bad band #%d\n", - me, band); - safe_write(err, buf, len); + fprintf(stderr, "%s: protocol error: bad band #%d\n", + me, band); return SIDEBAND_PROTOCOL_ERROR; } } diff --git a/sideband.h b/sideband.h index a84b6917c7..d72db35d1e 100644 --- a/sideband.h +++ b/sideband.h @@ -7,7 +7,7 @@ #define DEFAULT_PACKET_MAX 1000 #define LARGE_PACKET_MAX 65520 -int recv_sideband(const char *me, int in_stream, int out, int err); +int recv_sideband(const char *me, int in_stream, int out); ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max); #endif From 3db39264cd3334ae5e9ab933f0298540bbe389a5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 10 Mar 2009 22:58:09 +0100 Subject: [PATCH 0541/3720] winansi: support ESC [ K (erase in line) Signed-off-by: Johannes Schindelin Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/winansi.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index e2d96dfe6f..44dc293ad3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -18,8 +18,6 @@ This file is git-specific. Therefore, this file does not attempt to implement any codes that are not used by git. - - TODO: K */ static HANDLE console; @@ -79,6 +77,20 @@ static void set_console_attr(void) SetConsoleTextAttribute(console, attributes); } +static void erase_in_line(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + FillConsoleOutputCharacterA(console, ' ', + sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, + NULL); +} + + static const char *set_attr(const char *str) { const char *func; @@ -218,7 +230,7 @@ static const char *set_attr(const char *str) set_console_attr(); break; case 'K': - /* TODO */ + erase_in_line(); break; default: /* Unsupported code */ From f7512386097c4f20e3c147e5de8888e49e4835c5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 21 Mar 2009 01:20:57 +0100 Subject: [PATCH 0542/3720] Respect core.autocrlf when preparing temporary files for external diff When preparing temporary files for an external diff, the files should be handled as if they were worktree files. This makes things consistent for the case when one side of the diff was found in the current working directory (and therefore creating a temporary file could be avoided altogether). This fixes msysGit issue 177. Signed-off-by: Johannes Schindelin --- diff.c | 13 ++++++++++--- t/t4020-diff-external.sh | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/diff.c b/diff.c index 75d9fab8f8..699ae6aca3 100644 --- a/diff.c +++ b/diff.c @@ -1946,17 +1946,23 @@ void diff_free_filespec_data(struct diff_filespec *s) s->cnt_data = NULL; } -static void prep_temp_blob(struct diff_tempfile *temp, +static void prep_temp_blob(const char *path, struct diff_tempfile *temp, void *blob, unsigned long size, const unsigned char *sha1, int mode) { int fd; + struct strbuf buf = STRBUF_INIT; fd = git_mkstemp(temp->tmp_path, PATH_MAX, ".diff_XXXXXX"); if (fd < 0) die("unable to create temp-file: %s", strerror(errno)); + if (convert_to_working_tree(path, + (const char *)blob, (size_t)size, &buf)) { + blob = buf.buf; + size = buf.len; + } if (write_in_full(fd, blob, size) != size) die("unable to write temp-file"); close(fd); @@ -1964,6 +1970,7 @@ static void prep_temp_blob(struct diff_tempfile *temp, strcpy(temp->hex, sha1_to_hex(sha1)); temp->hex[40] = 0; sprintf(temp->mode, "%06o", mode); + strbuf_release(&buf); } static struct diff_tempfile *prepare_temp_file(const char *name, @@ -2004,7 +2011,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, die("readlink(%s)", name); if (ret == sizeof(buf)) die("symlink too long: %s", name); - prep_temp_blob(temp, buf, ret, + prep_temp_blob(name, temp, buf, ret, (one->sha1_valid ? one->sha1 : null_sha1), (one->sha1_valid ? @@ -2030,7 +2037,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, else { if (diff_populate_filespec(one, 0)) die("cannot read data blob for %s", one->path); - prep_temp_blob(temp, one->data, one->size, + prep_temp_blob(name, temp, one->data, one->size, one->sha1, one->mode); } return temp; diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 281680d95a..f8c99f1a98 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -136,4 +136,20 @@ test_expect_success 'GIT_EXTERNAL_DIFF with more than one changed files' ' GIT_EXTERNAL_DIFF=echo git diff ' +echo "#!$SHELL_PATH" >fake-diff.sh +cat >> fake-diff.sh <<\EOF +cat $2 >> crlfed.txt +EOF +chmod a+x fake-diff.sh + +keep_only_cr () { + tr -dc '\015' +} + +test_expect_success 'external diff with autocrlf = true' ' + git config core.autocrlf true && + GIT_EXTERNAL_DIFF=./fake-diff.sh git diff && + test $(wc -l < crlfed.txt) = $(cat crlfed.txt | keep_only_cr | wc -c) +' + test_done From d4eb98cedebe98918b58b30f19b216831098199e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Mar 2009 09:58:44 +0100 Subject: [PATCH 0543/3720] Undo MinGW specific test suite changes that are no longer needed The test failures are fixed meanwhile for various reasons: - Path mangling happens less often due to an updated MSYS-1.0.DLL. - pwd now always reports a Windows-style path (this was introduced in 4114156a). - The whitespace breakage in t1003 has mysteriously disappeared (perhaps due to a tool upgrade?) - The work-around in t4116 was fixed in 36adb4ab. Signed-off-by: Johannes Sixt --- t/t0001-init.sh | 2 +- t/t1003-read-tree-prefix.sh | 4 ---- t/t4116-apply-reverse.sh | 3 +-- t/t5505-remote.sh | 4 ---- t/t5511-refspec.sh | 23 +---------------------- t/t7201-co.sh | 6 +----- 6 files changed, 4 insertions(+), 38 deletions(-) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 41a36bb1a3..5ac0a273a9 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -108,7 +108,7 @@ test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' ' mkdir git-dir-wt-1.git && GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init ) && - check_config git-dir-wt-1.git false "$(pwd -W)" + check_config git-dir-wt-1.git false "$(pwd)" ' test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' ' diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh index c59ce72d94..8c6d67edda 100755 --- a/t/t1003-read-tree-prefix.sh +++ b/t/t1003-read-tree-prefix.sh @@ -8,10 +8,6 @@ test_description='git read-tree --prefix test. . ./test-lib.sh -cmp () { - diff -w "$@" -} - test_expect_success setup ' echo hello >one && git update-index --add one && diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 1f8743bfa6..2298ece801 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -42,8 +42,7 @@ test_expect_success 'apply in reverse' ' git reset --hard second && git apply --reverse --binary --index patch && git diff >diff && - : > empty && - test_cmp empty diff + test_cmp /dev/null diff ' diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 56b37ea432..5ec668d6d8 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -107,10 +107,6 @@ test_expect_success 'remove remote' ' ) ' -case $(uname -s) in -*MINGW*) pwd() { builtin pwd -W; } ;; -esac - test_expect_success 'remove remote protects non-remote branches' ' ( cd test && diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 0d27a28491..22ba380034 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -4,8 +4,6 @@ test_description='refspec parsing' . ./test-lib.sh -test_expect=test_expect_success - test_refspec () { kind=$1 refspec=$2 expect=$3 @@ -21,7 +19,7 @@ test_refspec () { title="$kind $refspec (invalid)" test='test_must_fail git ls-remote frotz' fi - $test_expect "$title" "$test" + test_expect_success "$title" "$test" } test_refspec push '' invalid @@ -51,14 +49,7 @@ test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' - -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid -test_expect=test_expect_success - test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid test_refspec push 'master~1:refs/remotes/frotz/backup' @@ -81,16 +72,4 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid -test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid -test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid - -test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid -test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid - -test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid -test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid - -test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*' -test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*' - test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 528b9f65b1..0e21632f19 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -207,11 +207,7 @@ test_expect_success 'checkout to detach HEAD with branchname^' ' fi ' -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac -$test_expect 'checkout to detach HEAD with :/message' ' +test_expect_success 'checkout to detach HEAD with :/message' ' git checkout -f master && git clean -f && git checkout ":/Initial" && From 20213ddd23407dc127e499cd59bc1b17989a90d1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 22 Mar 2009 04:59:20 -0400 Subject: [PATCH 0544/3720] remote: improve sorting of "configure for git push" list The data structure used to store this list is a string_list of sources with the destination in the util member. The current code just sorts on the source; if a single source is pushed to two different destination refs at a remote, then the order in which they are printed is non-deterministic. This patch implements a comparison using both fields. Besides being a little nicer on the eyes, giving a stable sort prevents false negatives in the test suite when comparing output. Signed-off-by: Jeff King --- builtin-remote.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/builtin-remote.c b/builtin-remote.c index 993acd6a09..9ef846f6a4 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -922,6 +922,20 @@ int add_push_to_show_info(struct string_list_item *push_item, void *cb_data) return 0; } +/* + * Sorting comparison for a string list that has push_info + * structs in its util field + */ +static int cmp_string_with_push(const void *va, const void *vb) +{ + const struct string_list_item *a = va; + const struct string_list_item *b = vb; + const struct push_info *a_push = a->util; + const struct push_info *b_push = b->util; + int cmp = strcmp(a->string, b->string); + return cmp ? cmp : strcmp(a_push->dest, b_push->dest); +} + int show_push_info_item(struct string_list_item *item, void *cb_data) { struct show_info *show_info = cb_data; @@ -1032,7 +1046,8 @@ static int show(int argc, const char **argv) info.width = info.width2 = 0; for_each_string_list(add_push_to_show_info, &states.push, &info); - sort_string_list(info.list); + qsort(info.list->items, info.list->nr, + sizeof(*info.list->items), cmp_string_with_push); if (info.list->nr) printf(" Local ref%s configured for 'git push'%s:\n", info.list->nr > 1 ? "s" : "", From bb6fe4e69c90fd9466412be55996e727f3e40cfa Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 25 Mar 2009 09:30:47 +0100 Subject: [PATCH 0545/3720] Redo part of the undone change in t5511 A bit too much was undone in d4eb98ce. Signed-off-by: Johannes Sixt --- t/t5511-refspec.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 22ba380034..c28932216b 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid + +test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid + +test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid + +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*' +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*' + test_done From d8f0692f7a0576f8fe4ca774d1227e802dd68a21 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Sep 2007 15:54:53 +0100 Subject: [PATCH 0546/3720] Revert bd2f73a6(Support the tools scripted in perl.) This is not needed in msysGit, since we call Perl from inside MSys, and therefore paths are handled gracefully. Incidentally, it fixes issue 46 (msysGit fails to install in paths beginning with C). This reverts bd2f73a6ba6daf6158112874414d338c7b0e528d. Signed-off-by: Johannes Schindelin --- perl/Makefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/perl/Makefile b/perl/Makefile index 2fefcd8bbb..e3dd1a5547 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -20,11 +20,7 @@ clean: $(RM) $(makfile).old ifdef NO_PERL_MAKEMAKER -# We exploit that /bin/sh transforms the DOS-Stype path in TEMP into -# the MSYS style pseudo-mount form. -# This colon-free from is needed because our perl scripts look at -# $(instdir_SQ) and split it at colons. -instdir_SQ = $(subst ','\'',$(shell cmd /x/d/c "set TEMP=$(prefix)/lib && sh -c 'echo \$$TEMP'")) +instdir_SQ = $(subst ','\'',$(prefix)/lib) $(makfile): ../GIT-CFLAGS Makefile echo all: private-Error.pm Git.pm > $@ echo ' mkdir -p blib/lib' >> $@ From 3fb2564c942a4fd094b47a809921cfef8270fd9f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:25:13 +0100 Subject: [PATCH 0547/3720] gitk: remove workaround for missing msgfmt In the meantime, gitk's Makefile has learnt to detect the absence of msgfmt and use the drop-in replacement in Tcl (which was developed for msysGit, but has been adopted both by gitk and git-gui). Signed-off-by: Johannes Schindelin --- gitk-git/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gitk-git/Makefile b/gitk-git/Makefile index 2dda57cbae..e1b6045605 100644 --- a/gitk-git/Makefile +++ b/gitk-git/Makefile @@ -19,10 +19,6 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) ## po-file creation rules XGETTEXT ?= xgettext -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') -ifneq (,$(findstring MINGW,$(uname_S))) - NO_MSGFMT=1 -endif ifdef NO_MSGFMT MSGFMT ?= $(TCL_PATH) po/po2msg.sh else From 2843e0e055d42a9f86ab508ca4de62c48d9bbf39 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 20:48:08 +0100 Subject: [PATCH 0548/3720] MinGW: the path separator to split GITPERLLIB is ';' on Win32 Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index aae3b09411..65b10c4569 100644 --- a/Makefile +++ b/Makefile @@ -215,6 +215,7 @@ ETC_GITCONFIG = etc/gitconfig endif lib = lib # DESTDIR= +pathsep = : # default configuration for gitweb GITWEB_CONFIG = gitweb_config.perl @@ -784,6 +785,7 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o endif ifneq (,$(findstring MINGW,$(uname_S))) + pathsep = ; NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_CURL = YesPlease @@ -1223,7 +1225,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl sed -e '1{' \ -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \ -e ' h' \ - -e ' s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ + -e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ -e ' H' \ -e ' x' \ -e '}' \ From a094080e8eec0bffcd17da6804ee09bc5309da6c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 22 Jan 2009 11:30:16 +0100 Subject: [PATCH 0549/3720] Do not issue the warning about the fallback of the PREFIX. It confuses gitk when it is browsing this repository on Windows. --- exec_cmd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 408e4e55e1..13e036fc37 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -28,9 +28,10 @@ const char *system_path(const char *path) !(prefix = strip_path_suffix(argv0_path, BINDIR)) && !(prefix = strip_path_suffix(argv0_path, "git"))) { prefix = PREFIX; - fprintf(stderr, "RUNTIME_PREFIX requested, " - "but prefix computation failed. " - "Using static fallback '%s'.\n", prefix); + /* + * RUNTIME_PREFIX requested, but prefix computation failed. + * Using static fallback. + */ } #endif From ccd3859ceb5622294f2a4b61524974a0c1ee22f7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 22 Jul 2008 13:42:58 +0200 Subject: [PATCH 0550/3720] Windows: Better support PAGER settings with spaces in the path On Windows, the pager was always run via a shell, which is not the case on Unix, where the shell variant was only used as a fallback. Thus, setting the pager, for example, like this: PAGER="C:/Program Files/msys/bin/less" would fail; an extra set of quotes is needed: PAGER="\"C:/Program Files/msys/bin/less\"" With this patch the former setting works as well. Signed-off-by: Johannes Sixt --- pager.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pager.c b/pager.c index 4921843577..77e9dd6ae4 100644 --- a/pager.c +++ b/pager.c @@ -9,7 +9,6 @@ static int spawned_pager; -#ifndef __MINGW32__ static void pager_preexec(void) { /* @@ -24,7 +23,6 @@ static void pager_preexec(void) setenv("LESS", "FRSX", 0); } -#endif static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; static struct child_process pager_process; @@ -68,13 +66,15 @@ void setup_pager(void) /* spawn the pager */ pager_argv[2] = pager; - pager_process.argv = pager_argv; - pager_process.in = -1; -#ifndef __MINGW32__ pager_process.preexec_cb = pager_preexec; -#endif - if (start_command(&pager_process)) - return; + pager_process.argv = &pager_argv[2]; + pager_process.in = -1; + if (start_command(&pager_process)) { + pager_process.argv = pager_argv; + pager_process.in = -1; + if (start_command(&pager_process)) + return; + } /* original process continues, but writes to the pipe */ dup2(pager_process.in, 1); From ddce70517e7486c64107f5ffd1383f0a3a2db34d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 26 Mar 2009 21:11:50 +0100 Subject: [PATCH 0551/3720] Skip tests that fail due to incomplete implementations, missing tools... --- t/Makefile | 24 ++++++++++++++++++++++++ t/t4150-am.sh | 6 +----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/t/Makefile b/t/Makefile index bf816fc850..a0ed388ba5 100644 --- a/t/Makefile +++ b/t/Makefile @@ -42,3 +42,27 @@ valgrind: GIT_TEST_OPTS=--valgrind $(MAKE) .PHONY: pre-clean $(T) aggregate-results clean valgrind + +-include Makefile.local + +GIT_SKIP_TESTS := $(GIT_SKIP_TESTS_LOCAL) +# git am does not treat absolute path to mbox file correctly +GIT_SKIP_TESTS += t4150.18 +# git upload-pack does not write an error message in this case +# (reason unknown; seems to be a race condition) +GIT_SKIP_TESTS += t5530.6 +# output contains CRLF (I think) +GIT_SKIP_TESTS += t7401.14 +# output contains CRLF (I think) +GIT_SKIP_TESTS += t7508.1[68] +# cannot run fake.sendmail for some reason +GIT_SKIP_TESTS += t9001 +# there's a problem with GIT_DIR in test 12 (why only there?) +# needs fixups with $PWD instead of $(pwd) - tries to run rsh c +GIT_SKIP_TESTS += t9200 +# CGI.pm not found +GIT_SKIP_TESTS += t9500 +export GIT_SKIP_TESTS + +NO_SVN_TESTS=SkipThem +export NO_SVN_TESTS diff --git a/t/t4150-am.sh b/t/t4150-am.sh index a8aa02e936..5e65afa0c1 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -245,11 +245,7 @@ test_expect_success 'am works from file (relative path given) in subdirectory' ' test -z "$(git diff second)" ' -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac -$test_expect 'am works from file (absolute path given) in subdirectory' ' +test_expect_success 'am works from file (absolute path given) in subdirectory' ' rm -fr subdir && git checkout first && P=$(pwd) && From 4eb0463971e7a806ac8b7cf4c6cfede2b7f4fff8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 13:42:51 +0100 Subject: [PATCH 0552/3720] Make report() from usage.c public as vreport(). We will use it for customized error reporting routines. --- git-compat-util.h | 1 + usage.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index f09f244061..d94c683e0c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -150,6 +150,7 @@ #endif /* General helper functions */ +extern void vreport(const char *prefix, const char *err, va_list params); extern void usage(const char *err) NORETURN; extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); diff --git a/usage.c b/usage.c index 820d09f92b..349f3fb350 100644 --- a/usage.c +++ b/usage.c @@ -5,7 +5,7 @@ */ #include "git-compat-util.h" -static void report(const char *prefix, const char *err, va_list params) +void vreport(const char *prefix, const char *err, va_list params) { char msg[1024]; vsnprintf(msg, sizeof(msg), err, params); @@ -20,18 +20,18 @@ static NORETURN void usage_builtin(const char *err) static NORETURN void die_builtin(const char *err, va_list params) { - report("fatal: ", err, params); + vreport("fatal: ", err, params); exit(128); } static void error_builtin(const char *err, va_list params) { - report("error: ", err, params); + vreport("error: ", err, params); } static void warn_builtin(const char *warn, va_list params) { - report("warning: ", warn, params); + vreport("warning: ", warn, params); } /* If we are in a dlopen()ed .so write to a global variable would segfault From 85763c86da5f0826a879f37056f2de033cb5ca12 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 13:46:37 +0100 Subject: [PATCH 0553/3720] Implement thread-specific die() routines; use one in start_async(). --- run-command.c | 16 ++++++++++++++++ t/Makefile | 3 --- usage.c | 32 +++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/run-command.c b/run-command.c index b05c734d05..09725b983f 100644 --- a/run-command.c +++ b/run-command.c @@ -293,9 +293,22 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const } #ifdef __MINGW32__ +static int close_fd = -1; +NORETURN void die_from_thread(const char *err, va_list params) +{ + vreport("fatal: ", err, params); + if (close_fd >= 0) + close(close_fd); + _endthreadex(128); + exit(128); /* silence compiler */ +} + static __stdcall unsigned run_thread(void *data) { struct async *async = data; + close_fd = async->fd_for_proc; + extern NORETURN void die_from_thread(const char *err, va_list params); + set_die_routine(die_from_thread); return async->proc(async->fd_for_proc, async->data); } #endif @@ -349,6 +362,9 @@ int finish_async(struct async *async) else if (!GetExitCodeThread(async->tid, &ret)) ret = error("cannot get thread exit code: %lu", GetLastError()); CloseHandle(async->tid); + if (ret) + /* test suite tests for this string */ + error("waitpid (async) failed"); #endif return ret; } diff --git a/t/Makefile b/t/Makefile index a0ed388ba5..9af58b9bc6 100644 --- a/t/Makefile +++ b/t/Makefile @@ -48,9 +48,6 @@ valgrind: GIT_SKIP_TESTS := $(GIT_SKIP_TESTS_LOCAL) # git am does not treat absolute path to mbox file correctly GIT_SKIP_TESTS += t4150.18 -# git upload-pack does not write an error message in this case -# (reason unknown; seems to be a race condition) -GIT_SKIP_TESTS += t5530.6 # output contains CRLF (I think) GIT_SKIP_TESTS += t7401.14 # output contains CRLF (I think) diff --git a/usage.c b/usage.c index 349f3fb350..9e35e8a390 100644 --- a/usage.c +++ b/usage.c @@ -34,16 +34,38 @@ static void warn_builtin(const char *warn, va_list params) vreport("warning: ", warn, params); } +typedef void (*die_fn_t)(const char *err, va_list params) NORETURN; + +static DWORD tls_index; + +static void tls_init(void) __attribute__((constructor)); +static void tls_init(void) +{ + tls_index = TlsAlloc(); +} + +struct routines { + die_fn_t die_routine; +}; /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ static void (*usage_routine)(const char *err) NORETURN = usage_builtin; -static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin; static void (*error_routine)(const char *err, va_list params) = error_builtin; static void (*warn_routine)(const char *err, va_list params) = warn_builtin; void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN) { - die_routine = routine; + struct routines *r = TlsGetValue(tls_index); + if (r == NULL) { + /* avoid die()! */ + r = calloc(sizeof(*r), 1); + if (r == NULL) { + fprintf(stderr, "cannot allocate thread-local storage"); + return; + } + TlsSetValue(tls_index, r); + } + r->die_routine = routine; } void usage(const char *err) @@ -54,9 +76,13 @@ void usage(const char *err) void die(const char *err, ...) { va_list params; + struct routines *r = TlsGetValue(tls_index); va_start(params, err); - die_routine(err, params); + if (r == NULL || r->die_routine == NULL) + die_builtin(err, params); + else + r->die_routine(err, params); va_end(params); } From f80f1db8b51e34741aa54eec93d1ce7b26655e78 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 16 Mar 2008 21:47:53 +0100 Subject: [PATCH 0554/3720] Need diff -u -b in t7401 because some lines end in CRLF. --- t/t7401-submodule-summary.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index d2d6d5be25..50030c1a49 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -14,6 +14,8 @@ esac . ./test-lib.sh +export GIT_TEST_CMP='diff -u -b' # some lines end in CRLF + add_file () { sm=$1 shift From fc7fe85cbcae92e5bfc68eb6d17b4857b704c1f7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 7 Nov 2007 11:19:00 +0100 Subject: [PATCH 0555/3720] gitk: Swap positions of 'next' and 'prev' buttons in the 'Find' section. The button order 'prev' left of 'next' feels more natural than the other way round, in particular, compared to the order of the forward and backward arrows that are in the line above. Signed-off-by: Johannes Sixt --- gitk-git/gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index a2c589f749..f43ca48dff 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2057,7 +2057,7 @@ proc makewindow {} { button .tf.lbar.fnext -text [mc "next"] -command {dofind 1 1} button .tf.lbar.fprev -text [mc "prev"] -command {dofind -1 1} label .tf.lbar.flab2 -text " [mc "commit"] " - pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \ + pack .tf.lbar.flabel .tf.lbar.fprev .tf.lbar.fnext .tf.lbar.flab2 \ -side left -fill y set gdttype [mc "containing:"] set gm [tk_optionMenu .tf.lbar.gdttype gdttype \ From 50f37d18b6c7c84ed81938226ca1bfbc00628fb8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 22 Jan 2009 11:26:41 +0100 Subject: [PATCH 0556/3720] Implement test-stat the prints the modification time. Compile with gcc -o test-stat -Wall test-stat.c -DEMULATE or gcc -o test-stat -Wall test-stat.c --- test-stat.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 test-stat.c diff --git a/test-stat.c b/test-stat.c new file mode 100644 index 0000000000..ff859412f0 --- /dev/null +++ b/test-stat.c @@ -0,0 +1,170 @@ +#include +#include +#include + +#ifdef EMULATE +#define HINT fprintf(stderr, "emulated stat\n") +#include +#include +#include + +/* Use mingw_lstat() instead of lstat()/stat() and + * mingw_fstat() instead of fstat() on Windows. + */ +int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_fstat(int fd, struct stat *buf); +#define fstat mingw_fstat +#define lstat mingw_lstat +#define stat(x,y) mingw_lstat(x,y) + +#define PATH_MAX 260 + +static inline int file_attr_to_st_mode (DWORD attr) +{ + int fMode = S_IREAD; + if (attr & FILE_ATTRIBUTE_DIRECTORY) + fMode |= S_IFDIR; + else + fMode |= S_IFREG; + if (!(attr & FILE_ATTRIBUTE_READONLY)) + fMode |= S_IWRITE; + return fMode; +} + +static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata) +{ + if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata)) + return 0; + + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_SHARING_BUFFER_EXCEEDED: + return EACCES; + case ERROR_BUFFER_OVERFLOW: + return ENAMETOOLONG; + case ERROR_NOT_ENOUGH_MEMORY: + return ENOMEM; + default: + return ENOENT; + } +} + +static inline time_t filetime_to_time_t(const FILETIME *ft) +{ + long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; + winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ + winTime /= 10000000; /* Nano to seconds resolution */ + return (time_t)winTime; +} + +/* We keep the do_lstat code in a separate function to avoid recursion. + * When a path ends with a slash, the stat will fail with ENOENT. In + * this case, we strip the trailing slashes and stat again. + */ +static int do_lstat(const char *file_name, struct stat *buf) +{ + WIN32_FILE_ATTRIBUTE_DATA fdata; + + if (!(errno = get_file_attr(file_name, &fdata))) { + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = 0; /* not used by Git */ + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + return 0; + } + return -1; +} + +/* We provide our own lstat/fstat functions, since the provided + * lstat/fstat functions are so slow. These stat functions are + * tailored for Git's usage (read: fast), and are not meant to be + * complete. Note that Git stat()s are redirected to mingw_lstat() + * too, since Windows doesn't really handle symlinks that well. + */ +int mingw_lstat(const char *file_name, struct stat *buf) +{ + int namelen; + static char alt_name[PATH_MAX]; + + if (!do_lstat(file_name, buf)) + return 0; + + /* if file_name ended in a '/', Windows returned ENOENT; + * try again without trailing slashes + */ + if (errno != ENOENT) + return -1; + + namelen = strlen(file_name); + if (namelen && file_name[namelen-1] != '/') + return -1; + while (namelen && file_name[namelen-1] == '/') + --namelen; + if (!namelen || namelen >= PATH_MAX) + return -1; + + memcpy(alt_name, file_name, namelen); + alt_name[namelen] = 0; + return do_lstat(alt_name, buf); +} + +#undef fstat +int mingw_fstat(int fd, struct stat *buf) +{ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + BY_HANDLE_FILE_INFORMATION fdata; + + if (fh == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + /* direct non-file handles to MS's fstat() */ + if (GetFileType(fh) != FILE_TYPE_DISK) + return fstat(fd, buf); + + if (GetFileInformationByHandle(fh, &fdata)) { + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = 0; /* not used by Git */ + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + return 0; + } + errno = EBADF; + return -1; +} + +#else +#define HINT (void)0 +#endif + +int main(int argc, char**argv) +{ + int i; + int err = 0; + HINT; + for (i = 1; i < argc; i++) + { + struct stat st; + if (stat(argv[i], &st)) { + perror(argv[i]); + err = 1; + continue; + } + printf("%s: %s\n", argv[i], ctime(&st.st_mtime)); + } + return err; +} From abd1fa1a1b8fa85962aa38dbb9465e68b09d1299 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 31 Mar 2009 15:09:06 +0200 Subject: [PATCH 0557/3720] test-suite: Log everything to a file in non-verbose mode Using 'return' from a test snippet is now a no-go because it would skip the assignment of the resulting exit code and it would also skip set +x. Signed-off-by: Johannes Sixt --- t/.gitignore | 1 + t/Makefile | 2 +- t/t0040-parse-options.sh | 3 + t/t1503-rev-parse-verify.sh | 1 + t/t5505-remote.sh | 1 + t/t6022-merge-rename.sh | 177 +++++++------------------------- t/t6034-merge-rename-nocruft.sh | 65 +++--------- t/t9300-fast-import.sh | 16 +-- t/test-lib.sh | 15 ++- 9 files changed, 68 insertions(+), 213 deletions(-) diff --git a/t/.gitignore b/t/.gitignore index 7dcbb232cd..dbe58eb9b3 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -1,2 +1,3 @@ /trash directory* /test-results +/test-log diff --git a/t/Makefile b/t/Makefile index 9af58b9bc6..6eefc08fea 100644 --- a/t/Makefile +++ b/t/Makefile @@ -21,7 +21,7 @@ $(T): @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) pre-clean: - $(RM) -r test-results + $(RM) -r test-results test-log clean: $(RM) -r 'trash directory'.* test-results diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index e38241c80a..da272e0124 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -39,6 +39,7 @@ Standard options EOF test_expect_success 'test help' ' + set +x && test_must_fail test-parse-options -h > output 2> output.err && test ! -s output && test_cmp expect.err output.err @@ -158,6 +159,7 @@ error: did you mean \`--boolean\` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' + set +x && test_must_fail test-parse-options -boolean > output 2> output.err && test ! -s output && test_cmp typo.err output.err @@ -223,6 +225,7 @@ Callback: "not set", 1 EOF test_expect_success 'OPT_CALLBACK() and callback errors work' ' + set +x && test_must_fail test-parse-options --no-length > output 2> output.err && test_cmp expect output && test_cmp expect.err output.err diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index cc65394947..4c677340f4 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -71,6 +71,7 @@ test_expect_success 'fails with any bad rev or many good revs' ' ' test_expect_success 'fails silently when using -q' ' + set +x && test_must_fail git rev-parse --verify --quiet 2>error && test -z "$(cat error)" && test_must_fail git rev-parse -q --verify foo 2>error && diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 5ec668d6d8..7267b1ae70 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -247,6 +247,7 @@ EOF test_expect_success 'set-head --auto fails w/multiple HEADs' ' (cd test && + set +x && test_must_fail git remote set-head --auto two >output 2>&1 && test_cmp expect output) ' diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index e3f7ae8120..d69a364cae 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -95,30 +95,15 @@ git checkout master' test_expect_success 'pull renaming branch into unrenaming one' \ ' git show-branch - git pull . white && { - echo "BAD: should have conflicted" - return 1 - } - git ls-files -s - test "$(git ls-files -u B | wc -l)" -eq 3 || { - echo "BAD: should have left stages for B" - return 1 - } - test "$(git ls-files -s N | wc -l)" -eq 1 || { - echo "BAD: should have merged N" - return 1 - } + test_must_fail git pull . white && + git ls-files -s && + test "$(git ls-files -u B | wc -l)" -eq 3 && + test "$(git ls-files -s N | wc -l)" -eq 1 && sed -ne "/^g/{ p q - }" B | grep master || { - echo "BAD: should have listed our change first" - return 1 - } - test "$(git diff white N | wc -l)" -eq 0 || { - echo "BAD: should have taken colored branch" - return 1 - } + }" B | grep master && + test "$(git diff white N | wc -l)" -eq 0 ' test_expect_success 'pull renaming branch into another renaming one' \ @@ -126,95 +111,44 @@ test_expect_success 'pull renaming branch into another renaming one' \ rm -f B git reset --hard git checkout red - git pull . white && { - echo "BAD: should have conflicted" - return 1 - } - test "$(git ls-files -u B | wc -l)" -eq 3 || { - echo "BAD: should have left stages" - return 1 - } - test "$(git ls-files -s N | wc -l)" -eq 1 || { - echo "BAD: should have merged N" - return 1 - } + test_must_fail git pull . white && + test "$(git ls-files -u B | wc -l)" -eq 3 && + test "$(git ls-files -s N | wc -l)" -eq 1 && sed -ne "/^g/{ p q - }" B | grep red || { - echo "BAD: should have listed our change first" - return 1 - } - test "$(git diff white N | wc -l)" -eq 0 || { - echo "BAD: should have taken colored branch" - return 1 - } + }" B | grep red && + test "$(git diff white N | wc -l)" -eq 0 ' test_expect_success 'pull unrenaming branch into renaming one' \ ' git reset --hard git show-branch - git pull . master && { - echo "BAD: should have conflicted" - return 1 - } - test "$(git ls-files -u B | wc -l)" -eq 3 || { - echo "BAD: should have left stages" - return 1 - } - test "$(git ls-files -s N | wc -l)" -eq 1 || { - echo "BAD: should have merged N" - return 1 - } + test_must_fail git pull . master && + test "$(git ls-files -u B | wc -l)" -eq 3 && + test "$(git ls-files -s N | wc -l)" -eq 1 && sed -ne "/^g/{ p q - }" B | grep red || { - echo "BAD: should have listed our change first" - return 1 - } - test "$(git diff white N | wc -l)" -eq 0 || { - echo "BAD: should have taken colored branch" - return 1 - } + }" B | grep red && + test "$(git diff white N | wc -l)" -eq 0 ' test_expect_success 'pull conflicting renames' \ ' git reset --hard git show-branch - git pull . blue && { - echo "BAD: should have conflicted" - return 1 - } - test "$(git ls-files -u A | wc -l)" -eq 1 || { - echo "BAD: should have left a stage" - return 1 - } - test "$(git ls-files -u B | wc -l)" -eq 1 || { - echo "BAD: should have left a stage" - return 1 - } - test "$(git ls-files -u C | wc -l)" -eq 1 || { - echo "BAD: should have left a stage" - return 1 - } - test "$(git ls-files -s N | wc -l)" -eq 1 || { - echo "BAD: should have merged N" - return 1 - } + test_must_fail git pull . blue && + test "$(git ls-files -u A | wc -l)" -eq 1 && + test "$(git ls-files -u B | wc -l)" -eq 1 && + test "$(git ls-files -u C | wc -l)" -eq 1 && + test "$(git ls-files -s N | wc -l)" -eq 1 && sed -ne "/^g/{ p q - }" B | grep red || { - echo "BAD: should have listed our change first" - return 1 - } - test "$(git diff white N | wc -l)" -eq 0 || { - echo "BAD: should have taken colored branch" - return 1 - } + }" B | grep red && + test "$(git diff white N | wc -l)" -eq 0 ' test_expect_success 'interference with untracked working tree file' ' @@ -222,14 +156,8 @@ test_expect_success 'interference with untracked working tree file' ' git reset --hard git show-branch echo >A this file should not matter - git pull . white && { - echo "BAD: should have conflicted" - return 1 - } - test -f A || { - echo "BAD: should have left A intact" - return 1 - } + test_must_fail git pull . white && + test -f A ' test_expect_success 'interference with untracked working tree file' ' @@ -239,14 +167,8 @@ test_expect_success 'interference with untracked working tree file' ' git show-branch rm -f A echo >A this file should not matter - git pull . red && { - echo "BAD: should have conflicted" - return 1 - } - test -f A || { - echo "BAD: should have left A intact" - return 1 - } + test_must_fail git pull . red && + test -f A ' test_expect_success 'interference with untracked working tree file' ' @@ -256,14 +178,8 @@ test_expect_success 'interference with untracked working tree file' ' git checkout -f master git tag -f anchor git show-branch - git pull . yellow || { - echo "BAD: should have cleanly merged" - return 1 - } - test -f M && { - echo "BAD: should have removed M" - return 1 - } + git pull . yellow + test ! -f M && git reset --hard anchor ' @@ -276,14 +192,8 @@ test_expect_success 'updated working tree file should prevent the merge' ' git show-branch echo >>M one line addition cat M >M.saved - git pull . yellow && { - echo "BAD: should have complained" - return 1 - } - diff M M.saved || { - echo "BAD: should have left M intact" - return 1 - } + test_must_fail git pull . yellow && + diff M M.saved && rm -f M.saved ' @@ -297,14 +207,8 @@ test_expect_success 'updated working tree file should prevent the merge' ' echo >>M one line addition cat M >M.saved git update-index M - git pull . yellow && { - echo "BAD: should have complained" - return 1 - } - diff M M.saved || { - echo "BAD: should have left M intact" - return 1 - } + test_must_fail git pull . yellow && + diff M M.saved && rm -f M.saved ' @@ -316,18 +220,9 @@ test_expect_success 'interference with untracked working tree file' ' git tag -f anchor git show-branch echo >M this file should not matter - git pull . master || { - echo "BAD: should have cleanly merged" - return 1 - } - test -f M || { - echo "BAD: should have left M intact" - return 1 - } - git ls-files -s | grep M && { - echo "BAD: M must be untracked in the result" - return 1 - } + git pull . master && + test -f M && + ! (git ls-files -s | grep M) && git reset --hard anchor ' diff --git a/t/t6034-merge-rename-nocruft.sh b/t/t6034-merge-rename-nocruft.sh index 65be95fbaa..d1b1d1a441 100755 --- a/t/t6034-merge-rename-nocruft.sh +++ b/t/t6034-merge-rename-nocruft.sh @@ -73,33 +73,12 @@ test_expect_success 'merge white into red (A->B,M->N)' \ ' git checkout -b red-white red && git merge white && - git write-tree >/dev/null || { - echo "BAD: merge did not complete" - return 1 - } - - test -f B || { - echo "BAD: B does not exist in working directory" - return 1 - } - test -f N || { - echo "BAD: N does not exist in working directory" - return 1 - } - test -f R || { - echo "BAD: R does not exist in working directory" - return 1 - } - - test -f A && { - echo "BAD: A still exists in working directory" - return 1 - } - test -f M && { - echo "BAD: M still exists in working directory" - return 1 - } - return 0 + git write-tree >/dev/null && + test -f B && + test -f N && + test -f R && + ! test -f A && + ! test -f M ' # This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9 @@ -108,32 +87,12 @@ test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \ git checkout -b white-blue white && echo dirty >A && git merge blue && - git write-tree >/dev/null || { - echo "BAD: merge did not complete" - return 1 - } - - test -f A || { - echo "BAD: A does not exist in working directory" - return 1 - } - test `cat A` = dirty || { - echo "BAD: A content is wrong" - return 1 - } - test -f B || { - echo "BAD: B does not exist in working directory" - return 1 - } - test -f N || { - echo "BAD: N does not exist in working directory" - return 1 - } - test -f M && { - echo "BAD: M still exists in working directory" - return 1 - } - return 0 + git write-tree >/dev/null && + test -f A && + test `cat A` = dirty && + test -f B && + test -f N && + ! test -f M ' test_done diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 821be7ce8d..a7a13b7e57 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -399,20 +399,8 @@ from refs/heads/branch INPUT_END test_expect_success \ 'F: non-fast-forward update skips' \ - 'if git fast-import &1 if test "$verbose" = "t" then + set_x= set_nox= exec 4>&2 3>&1 else - exec 4>/dev/null 3>/dev/null + test_log_dir="$TEST_DIRECTORY/test-log" + mkdir -p "$test_log_dir" + test_log_path="$test_log_dir/${0%.sh}-$$" + set_x='set -x;' + set_nox='set +x' + exec 3>"$test_log_path" 4>&3 fi test_failure=0 @@ -303,8 +310,9 @@ test_debug () { } test_run_ () { - eval >&3 2>&4 "$1" - eval_ret="$?" + eval >&3 2>&4 $set_x "$1" ' + eval_ret=$? + $set_nox' return 0 } @@ -540,7 +548,6 @@ test_done () { # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. -TEST_DIRECTORY=$(pwd) if test -z "$valgrind" then if test -z "$GIT_TEST_INSTALLED" From 1e52e22d9e874e135f0f724ef87d952afdfc5316 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 3 Apr 2009 08:49:59 +0200 Subject: [PATCH 0558/3720] Windows: Work around intermittent failures in mingw_rename We have replaced rename() with a version that can rename a file to a destination that already exists. Nevertheless, many users, the author included, observe failures in the code that are not reproducible. The theory is that the failures are due to some other process that happens to have opened the destination file briefly at the wrong moment. (And there is no way on Windows to delete or replace a file that is currently open.) One such process could be Windows Explorer that is updating its directory listing because it detected a change in the .git directory or a virus scanner. The failure is more often observed while there is heavy git activity (for example while the test suite is running or during a rebase operation). We work around the failure by retrying the rename operation if it failed due to ERROR_ACCESS_DENIED. The retries are delayed a bit: The first only by giving up the time slice, the next after the minimal scheduling granularity, and if more retries are needed, then we wait some non-trivial amount of time with exponential back-off. Signed-off-by: Johannes Sixt --- compat/mingw.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2839d9df6e..9f647e15cc 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -934,7 +934,9 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) #undef rename int mingw_rename(const char *pold, const char *pnew) { - DWORD attrs; + DWORD attrs, gle; + int tries = 0; + static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. @@ -944,10 +946,12 @@ int mingw_rename(const char *pold, const char *pnew) return 0; if (errno != EEXIST) return -1; +repeat: if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ - if (GetLastError() == ERROR_ACCESS_DENIED && + gle = GetLastError(); + if (gle == ERROR_ACCESS_DENIED && (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; @@ -957,10 +961,24 @@ int mingw_rename(const char *pold, const char *pnew) SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; + gle = GetLastError(); /* revert file attributes on failure */ SetFileAttributes(pnew, attrs); } } + if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) { + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + warning("rename retry #%d %s -> %s", tries, pold, pnew); + goto repeat; + } errno = EACCES; return -1; } From 7ee5b02494aadbe53e5a50f085ce0c81908b5781 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Sun, 5 Apr 2009 14:42:27 +0200 Subject: [PATCH 0559/3720] doc/merge-config: list ecmerge as a built-in merge tool Signed-off-by: Markus Heidelberg --- Documentation/merge-config.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 1ff08ff2cc..9c44af8e4a 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -22,7 +22,8 @@ merge.stat:: merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", - "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and + "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", + "ecmerge" and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool..cmd option. From 1fadfbe9b6df8f5e8733741986003f08ba9df2df Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Sun, 5 Apr 2009 14:42:57 +0200 Subject: [PATCH 0560/3720] git-mergetool/difftool: make (g)vimdiff workable under Windows Under Windows vimdiff and gvimdiff are not available as symbolic links, but as batch files vimdiff.bat and gvimdiff.bat. These files weren't found by 'type vimdiff' which led to the following error: The merge tool vimdiff is not available as 'vimdiff' Even if they were found, it wouldn't work to invoke these batch files from git-mergetool. To solve this, use vim and gvim (vim.exe and gvim.exe) and pass the -d command line switch over to them. Signed-off-by: Markus Heidelberg --- contrib/difftool/git-difftool-helper | 10 ++++++++-- git-mergetool.sh | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index 9c0a13452a..e481913c91 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -86,11 +86,11 @@ launch_merge_tool () { ;; vimdiff) - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" ;; gvimdiff) - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE" ;; xxdiff) @@ -160,6 +160,12 @@ init_merge_tool_path() { merge_tool_path=$(git config mergetool."$1".path) if test -z "$merge_tool_path"; then case "$1" in + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; emerge) merge_tool_path=emacs ;; diff --git a/git-mergetool.sh b/git-mergetool.sh index 87fa88af55..6e611e94a4 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -214,12 +214,12 @@ merge_file () { ;; vimdiff) touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" check_unchanged ;; gvimdiff) touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" check_unchanged ;; xxdiff) @@ -359,6 +359,12 @@ init_merge_tool_path() { merge_tool_path=`git config mergetool.$1.path` if test -z "$merge_tool_path" ; then case "$1" in + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; emerge) merge_tool_path=emacs ;; From 57d87482147e062ac1024f293f513a2400825fcb Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Sun, 5 Apr 2009 14:43:27 +0200 Subject: [PATCH 0561/3720] git-mergetool: add new merge tool TortoiseMerge TortoiseMerge comes with TortoiseSVN or TortoiseGit for Windows. It can only be used as a merge tool with an existing base file. It cannot be used without a base nor as a diff tool. The documentation only mentions the slash '/' as command line option prefix, which refused to work, but the parser also accepts the dash '-' See http://code.google.com/p/msysgit/issues/detail?id=226 Signed-off-by: Markus Heidelberg --- Documentation/git-mergetool.txt | 3 ++- Documentation/merge-config.txt | 2 +- git-mergetool.sh | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 5d3c632872..5edac4d267 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -26,7 +26,8 @@ OPTIONS --tool=:: Use the merge resolution program specified by . Valid merge tools are: - kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff + kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, + tortoisemerge and opendiff + If a merge resolution program is not specified, 'git-mergetool' will use the configuration variable `merge.tool`. If the diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 9c44af8e4a..8c10f66702 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -23,7 +23,7 @@ merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", - "ecmerge" and + "ecmerge", tortoisemerge and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool..cmd option. diff --git a/git-mergetool.sh b/git-mergetool.sh index 6e611e94a4..be9717a2f1 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -265,6 +265,16 @@ merge_file () { fi status=$? ;; + tortoisemerge) + if base_present ; then + touch "$BACKUP" + "$merge_tool_path" -base:"$BASE" -mine:"$LOCAL" -theirs:"$REMOTE" -merged:"$MERGED" + check_unchanged + else + echo "TortoiseMerge cannot be used without a base" 1>&2 + status=1 + fi + ;; *) if test -n "$merge_tool_cmd"; then if test "$merge_tool_trust_exit_code" = "false"; then @@ -345,7 +355,7 @@ valid_custom_tool() valid_tool() { case "$1" in - kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge) + kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge | tortoisemerge) ;; # happy *) if ! valid_custom_tool "$1"; then @@ -404,9 +414,9 @@ fi if test -z "$merge_tool" ; then if test -n "$DISPLAY"; then if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 tkdiff xxdiff gvimdiff" + merge_tool_candidates="meld kdiff3 tkdiff xxdiff tortoisemerge gvimdiff" else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff" + merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff" fi fi if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then From 7ba615a300fe2742e8d32f0313c6ee9a1a1aaed3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Apr 2009 17:40:03 +0200 Subject: [PATCH 0562/3720] Add a simple getpass() for MinGW This should be replaced with a graphical getpass() at some stage. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d50186e5f5..2ab5bbec1f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1157,3 +1157,18 @@ int link(const char *oldpath, const char *newpath) } return 0; } + +char *getpass(const char *prompt) +{ + struct strbuf buf = STRBUF_INIT; + + fputs(prompt, stderr); + for (;;) { + char c = _getch(); + if (c == '\r' || c == '\n') + break; + strbuf_addch(&buf, c); + } + fputs("\n", stderr); + return strbuf_detach(&buf, NULL); +} From 064f4d6929437a215874fc3defd1f22467ee8596 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Tue, 24 Mar 2009 13:00:33 -0400 Subject: [PATCH 0563/3720] Enable THREADED_DELTA_SEARCH for mingw Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b71bdd2421..9e2b41c4b1 100644 --- a/Makefile +++ b/Makefile @@ -811,7 +811,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR = YesPlease NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease From c04dd04f0fde515b59266b00fd8726a934763b5a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 11 Apr 2009 22:27:05 +0100 Subject: [PATCH 0564/3720] Mark t1301 permission test to depend on POSIXPERM Signed-off-by: Johannes Sixt --- t/t1301-shared-repo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 47a219680c..de42d21c92 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -126,7 +126,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' esac ' -test_expect_success 'forced modes' ' +test_expect_success POSIXPERM 'forced modes' ' mkdir -p templates/hooks && echo update-server-info >templates/hooks/post-update && chmod +x templates/hooks/post-update && From a36adafee41ad44aa35b419fe1db147964ac7128 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 13 Apr 2009 21:43:27 +0200 Subject: [PATCH 0565/3720] Revert accidentally merged commits This reverts the following commits: abd1fa1 test-suite: Log everything to a file in non-verbose mode 50f37d1 Implement test-stat the prints the modification time. fc7fe85 gitk: Swap positions of 'next' and 'prev' buttons in the 'Find' section. f80f1db Need diff -u -b in t7401 because some lines end in CRLF. 85763c8 Implement thread-specific die() routines; use one in start_async(). 4eb0463 Make report() from usage.c public as vreport(). ddce705 Skip tests that fail due to incomplete implementations, missing tools... a094080 Do not issue the warning about the fallback of the PREFIX. These were brought in by the merge commit dc8b641 that merged my private work-in-progress branch. Only these two commits remain: 1e52e22 Windows: Work around intermittent failures in mingw_rename ccd3859 Windows: Better support PAGER settings with spaces in the path Signed-off-by: Johannes Sixt --- exec_cmd.c | 7 +- git-compat-util.h | 1 - gitk-git/gitk | 2 +- run-command.c | 16 --- t/.gitignore | 1 - t/Makefile | 23 +---- t/t0040-parse-options.sh | 3 - t/t1503-rev-parse-verify.sh | 1 - t/t4150-am.sh | 6 +- t/t5505-remote.sh | 1 - t/t6022-merge-rename.sh | 177 +++++++++++++++++++++++++------- t/t6034-merge-rename-nocruft.sh | 65 +++++++++--- t/t7401-submodule-summary.sh | 2 - t/t9300-fast-import.sh | 16 ++- t/test-lib.sh | 15 +-- test-stat.c | 170 ------------------------------ usage.c | 40 ++------ 17 files changed, 229 insertions(+), 317 deletions(-) delete mode 100644 test-stat.c diff --git a/exec_cmd.c b/exec_cmd.c index 13e036fc37..408e4e55e1 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -28,10 +28,9 @@ const char *system_path(const char *path) !(prefix = strip_path_suffix(argv0_path, BINDIR)) && !(prefix = strip_path_suffix(argv0_path, "git"))) { prefix = PREFIX; - /* - * RUNTIME_PREFIX requested, but prefix computation failed. - * Using static fallback. - */ + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); } #endif diff --git a/git-compat-util.h b/git-compat-util.h index d94c683e0c..f09f244061 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -150,7 +150,6 @@ #endif /* General helper functions */ -extern void vreport(const char *prefix, const char *err, va_list params); extern void usage(const char *err) NORETURN; extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); diff --git a/gitk-git/gitk b/gitk-git/gitk index f43ca48dff..a2c589f749 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2057,7 +2057,7 @@ proc makewindow {} { button .tf.lbar.fnext -text [mc "next"] -command {dofind 1 1} button .tf.lbar.fprev -text [mc "prev"] -command {dofind -1 1} label .tf.lbar.flab2 -text " [mc "commit"] " - pack .tf.lbar.flabel .tf.lbar.fprev .tf.lbar.fnext .tf.lbar.flab2 \ + pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \ -side left -fill y set gdttype [mc "containing:"] set gm [tk_optionMenu .tf.lbar.gdttype gdttype \ diff --git a/run-command.c b/run-command.c index 09725b983f..b05c734d05 100644 --- a/run-command.c +++ b/run-command.c @@ -293,22 +293,9 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const } #ifdef __MINGW32__ -static int close_fd = -1; -NORETURN void die_from_thread(const char *err, va_list params) -{ - vreport("fatal: ", err, params); - if (close_fd >= 0) - close(close_fd); - _endthreadex(128); - exit(128); /* silence compiler */ -} - static __stdcall unsigned run_thread(void *data) { struct async *async = data; - close_fd = async->fd_for_proc; - extern NORETURN void die_from_thread(const char *err, va_list params); - set_die_routine(die_from_thread); return async->proc(async->fd_for_proc, async->data); } #endif @@ -362,9 +349,6 @@ int finish_async(struct async *async) else if (!GetExitCodeThread(async->tid, &ret)) ret = error("cannot get thread exit code: %lu", GetLastError()); CloseHandle(async->tid); - if (ret) - /* test suite tests for this string */ - error("waitpid (async) failed"); #endif return ret; } diff --git a/t/.gitignore b/t/.gitignore index dbe58eb9b3..7dcbb232cd 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -1,3 +1,2 @@ /trash directory* /test-results -/test-log diff --git a/t/Makefile b/t/Makefile index 6eefc08fea..bf816fc850 100644 --- a/t/Makefile +++ b/t/Makefile @@ -21,7 +21,7 @@ $(T): @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) pre-clean: - $(RM) -r test-results test-log + $(RM) -r test-results clean: $(RM) -r 'trash directory'.* test-results @@ -42,24 +42,3 @@ valgrind: GIT_TEST_OPTS=--valgrind $(MAKE) .PHONY: pre-clean $(T) aggregate-results clean valgrind - --include Makefile.local - -GIT_SKIP_TESTS := $(GIT_SKIP_TESTS_LOCAL) -# git am does not treat absolute path to mbox file correctly -GIT_SKIP_TESTS += t4150.18 -# output contains CRLF (I think) -GIT_SKIP_TESTS += t7401.14 -# output contains CRLF (I think) -GIT_SKIP_TESTS += t7508.1[68] -# cannot run fake.sendmail for some reason -GIT_SKIP_TESTS += t9001 -# there's a problem with GIT_DIR in test 12 (why only there?) -# needs fixups with $PWD instead of $(pwd) - tries to run rsh c -GIT_SKIP_TESTS += t9200 -# CGI.pm not found -GIT_SKIP_TESTS += t9500 -export GIT_SKIP_TESTS - -NO_SVN_TESTS=SkipThem -export NO_SVN_TESTS diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index da272e0124..e38241c80a 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -39,7 +39,6 @@ Standard options EOF test_expect_success 'test help' ' - set +x && test_must_fail test-parse-options -h > output 2> output.err && test ! -s output && test_cmp expect.err output.err @@ -159,7 +158,6 @@ error: did you mean \`--boolean\` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' - set +x && test_must_fail test-parse-options -boolean > output 2> output.err && test ! -s output && test_cmp typo.err output.err @@ -225,7 +223,6 @@ Callback: "not set", 1 EOF test_expect_success 'OPT_CALLBACK() and callback errors work' ' - set +x && test_must_fail test-parse-options --no-length > output 2> output.err && test_cmp expect output && test_cmp expect.err output.err diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index 4c677340f4..cc65394947 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -71,7 +71,6 @@ test_expect_success 'fails with any bad rev or many good revs' ' ' test_expect_success 'fails silently when using -q' ' - set +x && test_must_fail git rev-parse --verify --quiet 2>error && test -z "$(cat error)" && test_must_fail git rev-parse -q --verify foo 2>error && diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 5e65afa0c1..a8aa02e936 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -245,7 +245,11 @@ test_expect_success 'am works from file (relative path given) in subdirectory' ' test -z "$(git diff second)" ' -test_expect_success 'am works from file (absolute path given) in subdirectory' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'am works from file (absolute path given) in subdirectory' ' rm -fr subdir && git checkout first && P=$(pwd) && diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 7267b1ae70..5ec668d6d8 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -247,7 +247,6 @@ EOF test_expect_success 'set-head --auto fails w/multiple HEADs' ' (cd test && - set +x && test_must_fail git remote set-head --auto two >output 2>&1 && test_cmp expect output) ' diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index d69a364cae..e3f7ae8120 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -95,15 +95,30 @@ git checkout master' test_expect_success 'pull renaming branch into unrenaming one' \ ' git show-branch - test_must_fail git pull . white && - git ls-files -s && - test "$(git ls-files -u B | wc -l)" -eq 3 && - test "$(git ls-files -s N | wc -l)" -eq 1 && + git pull . white && { + echo "BAD: should have conflicted" + return 1 + } + git ls-files -s + test "$(git ls-files -u B | wc -l)" -eq 3 || { + echo "BAD: should have left stages for B" + return 1 + } + test "$(git ls-files -s N | wc -l)" -eq 1 || { + echo "BAD: should have merged N" + return 1 + } sed -ne "/^g/{ p q - }" B | grep master && - test "$(git diff white N | wc -l)" -eq 0 + }" B | grep master || { + echo "BAD: should have listed our change first" + return 1 + } + test "$(git diff white N | wc -l)" -eq 0 || { + echo "BAD: should have taken colored branch" + return 1 + } ' test_expect_success 'pull renaming branch into another renaming one' \ @@ -111,44 +126,95 @@ test_expect_success 'pull renaming branch into another renaming one' \ rm -f B git reset --hard git checkout red - test_must_fail git pull . white && - test "$(git ls-files -u B | wc -l)" -eq 3 && - test "$(git ls-files -s N | wc -l)" -eq 1 && + git pull . white && { + echo "BAD: should have conflicted" + return 1 + } + test "$(git ls-files -u B | wc -l)" -eq 3 || { + echo "BAD: should have left stages" + return 1 + } + test "$(git ls-files -s N | wc -l)" -eq 1 || { + echo "BAD: should have merged N" + return 1 + } sed -ne "/^g/{ p q - }" B | grep red && - test "$(git diff white N | wc -l)" -eq 0 + }" B | grep red || { + echo "BAD: should have listed our change first" + return 1 + } + test "$(git diff white N | wc -l)" -eq 0 || { + echo "BAD: should have taken colored branch" + return 1 + } ' test_expect_success 'pull unrenaming branch into renaming one' \ ' git reset --hard git show-branch - test_must_fail git pull . master && - test "$(git ls-files -u B | wc -l)" -eq 3 && - test "$(git ls-files -s N | wc -l)" -eq 1 && + git pull . master && { + echo "BAD: should have conflicted" + return 1 + } + test "$(git ls-files -u B | wc -l)" -eq 3 || { + echo "BAD: should have left stages" + return 1 + } + test "$(git ls-files -s N | wc -l)" -eq 1 || { + echo "BAD: should have merged N" + return 1 + } sed -ne "/^g/{ p q - }" B | grep red && - test "$(git diff white N | wc -l)" -eq 0 + }" B | grep red || { + echo "BAD: should have listed our change first" + return 1 + } + test "$(git diff white N | wc -l)" -eq 0 || { + echo "BAD: should have taken colored branch" + return 1 + } ' test_expect_success 'pull conflicting renames' \ ' git reset --hard git show-branch - test_must_fail git pull . blue && - test "$(git ls-files -u A | wc -l)" -eq 1 && - test "$(git ls-files -u B | wc -l)" -eq 1 && - test "$(git ls-files -u C | wc -l)" -eq 1 && - test "$(git ls-files -s N | wc -l)" -eq 1 && + git pull . blue && { + echo "BAD: should have conflicted" + return 1 + } + test "$(git ls-files -u A | wc -l)" -eq 1 || { + echo "BAD: should have left a stage" + return 1 + } + test "$(git ls-files -u B | wc -l)" -eq 1 || { + echo "BAD: should have left a stage" + return 1 + } + test "$(git ls-files -u C | wc -l)" -eq 1 || { + echo "BAD: should have left a stage" + return 1 + } + test "$(git ls-files -s N | wc -l)" -eq 1 || { + echo "BAD: should have merged N" + return 1 + } sed -ne "/^g/{ p q - }" B | grep red && - test "$(git diff white N | wc -l)" -eq 0 + }" B | grep red || { + echo "BAD: should have listed our change first" + return 1 + } + test "$(git diff white N | wc -l)" -eq 0 || { + echo "BAD: should have taken colored branch" + return 1 + } ' test_expect_success 'interference with untracked working tree file' ' @@ -156,8 +222,14 @@ test_expect_success 'interference with untracked working tree file' ' git reset --hard git show-branch echo >A this file should not matter - test_must_fail git pull . white && - test -f A + git pull . white && { + echo "BAD: should have conflicted" + return 1 + } + test -f A || { + echo "BAD: should have left A intact" + return 1 + } ' test_expect_success 'interference with untracked working tree file' ' @@ -167,8 +239,14 @@ test_expect_success 'interference with untracked working tree file' ' git show-branch rm -f A echo >A this file should not matter - test_must_fail git pull . red && - test -f A + git pull . red && { + echo "BAD: should have conflicted" + return 1 + } + test -f A || { + echo "BAD: should have left A intact" + return 1 + } ' test_expect_success 'interference with untracked working tree file' ' @@ -178,8 +256,14 @@ test_expect_success 'interference with untracked working tree file' ' git checkout -f master git tag -f anchor git show-branch - git pull . yellow - test ! -f M && + git pull . yellow || { + echo "BAD: should have cleanly merged" + return 1 + } + test -f M && { + echo "BAD: should have removed M" + return 1 + } git reset --hard anchor ' @@ -192,8 +276,14 @@ test_expect_success 'updated working tree file should prevent the merge' ' git show-branch echo >>M one line addition cat M >M.saved - test_must_fail git pull . yellow && - diff M M.saved && + git pull . yellow && { + echo "BAD: should have complained" + return 1 + } + diff M M.saved || { + echo "BAD: should have left M intact" + return 1 + } rm -f M.saved ' @@ -207,8 +297,14 @@ test_expect_success 'updated working tree file should prevent the merge' ' echo >>M one line addition cat M >M.saved git update-index M - test_must_fail git pull . yellow && - diff M M.saved && + git pull . yellow && { + echo "BAD: should have complained" + return 1 + } + diff M M.saved || { + echo "BAD: should have left M intact" + return 1 + } rm -f M.saved ' @@ -220,9 +316,18 @@ test_expect_success 'interference with untracked working tree file' ' git tag -f anchor git show-branch echo >M this file should not matter - git pull . master && - test -f M && - ! (git ls-files -s | grep M) && + git pull . master || { + echo "BAD: should have cleanly merged" + return 1 + } + test -f M || { + echo "BAD: should have left M intact" + return 1 + } + git ls-files -s | grep M && { + echo "BAD: M must be untracked in the result" + return 1 + } git reset --hard anchor ' diff --git a/t/t6034-merge-rename-nocruft.sh b/t/t6034-merge-rename-nocruft.sh index d1b1d1a441..65be95fbaa 100755 --- a/t/t6034-merge-rename-nocruft.sh +++ b/t/t6034-merge-rename-nocruft.sh @@ -73,12 +73,33 @@ test_expect_success 'merge white into red (A->B,M->N)' \ ' git checkout -b red-white red && git merge white && - git write-tree >/dev/null && - test -f B && - test -f N && - test -f R && - ! test -f A && - ! test -f M + git write-tree >/dev/null || { + echo "BAD: merge did not complete" + return 1 + } + + test -f B || { + echo "BAD: B does not exist in working directory" + return 1 + } + test -f N || { + echo "BAD: N does not exist in working directory" + return 1 + } + test -f R || { + echo "BAD: R does not exist in working directory" + return 1 + } + + test -f A && { + echo "BAD: A still exists in working directory" + return 1 + } + test -f M && { + echo "BAD: M still exists in working directory" + return 1 + } + return 0 ' # This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9 @@ -87,12 +108,32 @@ test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \ git checkout -b white-blue white && echo dirty >A && git merge blue && - git write-tree >/dev/null && - test -f A && - test `cat A` = dirty && - test -f B && - test -f N && - ! test -f M + git write-tree >/dev/null || { + echo "BAD: merge did not complete" + return 1 + } + + test -f A || { + echo "BAD: A does not exist in working directory" + return 1 + } + test `cat A` = dirty || { + echo "BAD: A content is wrong" + return 1 + } + test -f B || { + echo "BAD: B does not exist in working directory" + return 1 + } + test -f N || { + echo "BAD: N does not exist in working directory" + return 1 + } + test -f M && { + echo "BAD: M still exists in working directory" + return 1 + } + return 0 ' test_done diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 50030c1a49..d2d6d5be25 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -14,8 +14,6 @@ esac . ./test-lib.sh -export GIT_TEST_CMP='diff -u -b' # some lines end in CRLF - add_file () { sm=$1 shift diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index a7a13b7e57..821be7ce8d 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -399,8 +399,20 @@ from refs/heads/branch INPUT_END test_expect_success \ 'F: non-fast-forward update skips' \ - 'test_must_fail git fast-import &1 if test "$verbose" = "t" then - set_x= set_nox= exec 4>&2 3>&1 else - test_log_dir="$TEST_DIRECTORY/test-log" - mkdir -p "$test_log_dir" - test_log_path="$test_log_dir/${0%.sh}-$$" - set_x='set -x;' - set_nox='set +x' - exec 3>"$test_log_path" 4>&3 + exec 4>/dev/null 3>/dev/null fi test_failure=0 @@ -310,9 +303,8 @@ test_debug () { } test_run_ () { - eval >&3 2>&4 $set_x "$1" ' - eval_ret=$? - $set_nox' + eval >&3 2>&4 "$1" + eval_ret="$?" return 0 } @@ -548,6 +540,7 @@ test_done () { # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. +TEST_DIRECTORY=$(pwd) if test -z "$valgrind" then if test -z "$GIT_TEST_INSTALLED" diff --git a/test-stat.c b/test-stat.c deleted file mode 100644 index ff859412f0..0000000000 --- a/test-stat.c +++ /dev/null @@ -1,170 +0,0 @@ -#include -#include -#include - -#ifdef EMULATE -#define HINT fprintf(stderr, "emulated stat\n") -#include -#include -#include - -/* Use mingw_lstat() instead of lstat()/stat() and - * mingw_fstat() instead of fstat() on Windows. - */ -int mingw_lstat(const char *file_name, struct stat *buf); -int mingw_fstat(int fd, struct stat *buf); -#define fstat mingw_fstat -#define lstat mingw_lstat -#define stat(x,y) mingw_lstat(x,y) - -#define PATH_MAX 260 - -static inline int file_attr_to_st_mode (DWORD attr) -{ - int fMode = S_IREAD; - if (attr & FILE_ATTRIBUTE_DIRECTORY) - fMode |= S_IFDIR; - else - fMode |= S_IFREG; - if (!(attr & FILE_ATTRIBUTE_READONLY)) - fMode |= S_IWRITE; - return fMode; -} - -static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata) -{ - if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata)) - return 0; - - switch (GetLastError()) { - case ERROR_ACCESS_DENIED: - case ERROR_SHARING_VIOLATION: - case ERROR_LOCK_VIOLATION: - case ERROR_SHARING_BUFFER_EXCEEDED: - return EACCES; - case ERROR_BUFFER_OVERFLOW: - return ENAMETOOLONG; - case ERROR_NOT_ENOUGH_MEMORY: - return ENOMEM; - default: - return ENOENT; - } -} - -static inline time_t filetime_to_time_t(const FILETIME *ft) -{ - long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; - winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ - winTime /= 10000000; /* Nano to seconds resolution */ - return (time_t)winTime; -} - -/* We keep the do_lstat code in a separate function to avoid recursion. - * When a path ends with a slash, the stat will fail with ENOENT. In - * this case, we strip the trailing slashes and stat again. - */ -static int do_lstat(const char *file_name, struct stat *buf) -{ - WIN32_FILE_ATTRIBUTE_DATA fdata; - - if (!(errno = get_file_attr(file_name, &fdata))) { - buf->st_ino = 0; - buf->st_gid = 0; - buf->st_uid = 0; - buf->st_nlink = 1; - buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = 0; /* not used by Git */ - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); - return 0; - } - return -1; -} - -/* We provide our own lstat/fstat functions, since the provided - * lstat/fstat functions are so slow. These stat functions are - * tailored for Git's usage (read: fast), and are not meant to be - * complete. Note that Git stat()s are redirected to mingw_lstat() - * too, since Windows doesn't really handle symlinks that well. - */ -int mingw_lstat(const char *file_name, struct stat *buf) -{ - int namelen; - static char alt_name[PATH_MAX]; - - if (!do_lstat(file_name, buf)) - return 0; - - /* if file_name ended in a '/', Windows returned ENOENT; - * try again without trailing slashes - */ - if (errno != ENOENT) - return -1; - - namelen = strlen(file_name); - if (namelen && file_name[namelen-1] != '/') - return -1; - while (namelen && file_name[namelen-1] == '/') - --namelen; - if (!namelen || namelen >= PATH_MAX) - return -1; - - memcpy(alt_name, file_name, namelen); - alt_name[namelen] = 0; - return do_lstat(alt_name, buf); -} - -#undef fstat -int mingw_fstat(int fd, struct stat *buf) -{ - HANDLE fh = (HANDLE)_get_osfhandle(fd); - BY_HANDLE_FILE_INFORMATION fdata; - - if (fh == INVALID_HANDLE_VALUE) { - errno = EBADF; - return -1; - } - /* direct non-file handles to MS's fstat() */ - if (GetFileType(fh) != FILE_TYPE_DISK) - return fstat(fd, buf); - - if (GetFileInformationByHandle(fh, &fdata)) { - buf->st_ino = 0; - buf->st_gid = 0; - buf->st_uid = 0; - buf->st_nlink = 1; - buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = 0; /* not used by Git */ - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); - return 0; - } - errno = EBADF; - return -1; -} - -#else -#define HINT (void)0 -#endif - -int main(int argc, char**argv) -{ - int i; - int err = 0; - HINT; - for (i = 1; i < argc; i++) - { - struct stat st; - if (stat(argv[i], &st)) { - perror(argv[i]); - err = 1; - continue; - } - printf("%s: %s\n", argv[i], ctime(&st.st_mtime)); - } - return err; -} diff --git a/usage.c b/usage.c index 9e35e8a390..820d09f92b 100644 --- a/usage.c +++ b/usage.c @@ -5,7 +5,7 @@ */ #include "git-compat-util.h" -void vreport(const char *prefix, const char *err, va_list params) +static void report(const char *prefix, const char *err, va_list params) { char msg[1024]; vsnprintf(msg, sizeof(msg), err, params); @@ -20,52 +20,30 @@ static NORETURN void usage_builtin(const char *err) static NORETURN void die_builtin(const char *err, va_list params) { - vreport("fatal: ", err, params); + report("fatal: ", err, params); exit(128); } static void error_builtin(const char *err, va_list params) { - vreport("error: ", err, params); + report("error: ", err, params); } static void warn_builtin(const char *warn, va_list params) { - vreport("warning: ", warn, params); + report("warning: ", warn, params); } -typedef void (*die_fn_t)(const char *err, va_list params) NORETURN; - -static DWORD tls_index; - -static void tls_init(void) __attribute__((constructor)); -static void tls_init(void) -{ - tls_index = TlsAlloc(); -} - -struct routines { - die_fn_t die_routine; -}; /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ static void (*usage_routine)(const char *err) NORETURN = usage_builtin; +static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin; static void (*error_routine)(const char *err, va_list params) = error_builtin; static void (*warn_routine)(const char *err, va_list params) = warn_builtin; void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN) { - struct routines *r = TlsGetValue(tls_index); - if (r == NULL) { - /* avoid die()! */ - r = calloc(sizeof(*r), 1); - if (r == NULL) { - fprintf(stderr, "cannot allocate thread-local storage"); - return; - } - TlsSetValue(tls_index, r); - } - r->die_routine = routine; + die_routine = routine; } void usage(const char *err) @@ -76,13 +54,9 @@ void usage(const char *err) void die(const char *err, ...) { va_list params; - struct routines *r = TlsGetValue(tls_index); va_start(params, err); - if (r == NULL || r->die_routine == NULL) - die_builtin(err, params); - else - r->die_routine(err, params); + die_routine(err, params); va_end(params); } From 3d3ecb65e34a62b83648516150ec8a99e1b3ace7 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 15 Apr 2009 17:14:03 +0100 Subject: [PATCH 0566/3720] gitk: avoid crash if closed while reading references As recorded in msysGit issue 125 if the user closes gitk while it reports itself as still reading references then Tk will crash in the geometry management code. This has been fixed for Tk 8.5.7 and above. This patch avoids the problem by flushing outstanding geometry events before calling the readrefs procedure. See also http://code.google.com/p/msysgit/issues/detail?id=125 Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index a2c589f749..e78459feda 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -10887,6 +10887,7 @@ makewindow # wait for the window to become visible tkwait visibility . wm title . "[file tail $argv0]: [file tail [pwd]]" +update readrefs if {$cmdline_files ne {} || $revtreeargs ne {} || $revtreeargscmd ne {}} { From 933833643ac7e5c08cb8ea3cb00e1fa128e57960 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 19 Apr 2009 17:27:59 +0200 Subject: [PATCH 0567/3720] Makefile: Clean up after USE_WIN32_MMAP went upstream This commit removes left overs of 7e5a4c563667d011c0655679be3190461884a78e, which was applied by Junio in a slightly modified version in b130a72b274441bb5d687de93efef4d990c40c0a. --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index 9e2b41c4b1..b851df818a 100644 --- a/Makefile +++ b/Makefile @@ -1010,10 +1010,6 @@ else COMPAT_OBJS += compat/win32mmap.o endif endif -ifdef USE_WIN32_MMAP - COMPAT_CFLAGS += -DUSE_WIN32_MMAP - COMPAT_OBJS += compat/win32mmap.o -endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD COMPAT_OBJS += compat/pread.o From aa3abfc9852a4d4cfaa7f0042102eb56ed2e0daa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 20 Apr 2009 21:43:11 +0200 Subject: [PATCH 0568/3720] Work around a regression in Windows 7, causing erase_in_line() to crash sometimes The function FillConsoleOutputCharacterA() was pretty content in XP to take a NULL pointer if we did not want to store the number of written columns. In Windows 7, it crashes, but only when called from within Git Bash, not from within cmd.exe. Go figure. Signed-off-by: Johannes Schindelin --- compat/winansi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/winansi.c b/compat/winansi.c index 44dc293ad3..4bee335f9e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -80,6 +80,7 @@ static void set_console_attr(void) static void erase_in_line(void) { CONSOLE_SCREEN_BUFFER_INFO sbi; + long dummy; /* Needed for Windows 7 (or Vista) regression */ if (!console) return; @@ -87,7 +88,7 @@ static void erase_in_line(void) GetConsoleScreenBufferInfo(console, &sbi); FillConsoleOutputCharacterA(console, ' ', sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, - NULL); + &dummy); } From aea0a0601b58268e40e60441567d004f47de72f3 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Wed, 1 Apr 2009 14:10:24 +0200 Subject: [PATCH 0569/3720] Add custom memory allocator to MinGW and MacOS builds The standard allocator on Windows is pretty bad prior to Windows Vista, and nedmalloc is better than the modified dlmalloc provided with newer versions of the MinGW libc. NedMalloc stats in Git ---------------------- All results are the best result out of 3 runs. The benchmarks have been done on different hardware, so the repack times are not comparable. These benchmarks are all based on 'git repack -adf' on the Linux kernel. XP ----------------------------------------------- MinGW Threads Total Time Speed ----------------------------------------------- 3.4.2 (1T) 00:12:28.422 3.4.2 + nedmalloc (1T) 00:07:25.437 1.68x 3.4.5 (1T) 00:12:20.718 3.4.5 + nedmalloc (1T) 00:07:24.809 1.67x 4.3.3-tdm (1T) 00:12:01.843 4.3.3-tdm + nedmalloc (1T) 00:07:16.468 1.65x 4.3.3-tdm (2T) 00:07:35.062 4.3.3-tdm + nedmalloc (2T) 00:04:57.874 1.54x Vista ----------------------------------------------- MinGW Threads Total Time Speed ----------------------------------------------- 4.3.3-tdm (1T) 00:07:40.844 4.3.3-tdm + nedmalloc (1T) 00:07:17.548 1.05x 4.3.3-tdm (2T) 00:05:33.746 4.3.3-tdm + nedmalloc (2T) 00:05:27.334 1.02x Mac Mini ----------------------------------------------- GCC Threads Total Time Speed ----------------------------------------------- i686-darwin9-4.0.1 (2T) 00:09:57.346 i686-darwin9-4.0.1+ned (2T) 00:08:51.072 1.12x Signed-off-by: Marius Storm-Olsen --- Makefile | 9 + compat/nedmalloc/License.txt | 23 + compat/nedmalloc/Readme.txt | 136 + compat/nedmalloc/malloc.c.h | 5750 ++++++++++++++++++++++++++++++++++ compat/nedmalloc/nedmalloc.c | 966 ++++++ compat/nedmalloc/nedmalloc.h | 180 ++ 6 files changed, 7064 insertions(+) create mode 100644 compat/nedmalloc/License.txt create mode 100644 compat/nedmalloc/Readme.txt create mode 100644 compat/nedmalloc/malloc.c.h create mode 100644 compat/nedmalloc/nedmalloc.c create mode 100644 compat/nedmalloc/nedmalloc.h diff --git a/Makefile b/Makefile index b851df818a..bec8a4229e 100644 --- a/Makefile +++ b/Makefile @@ -165,6 +165,9 @@ all:: # Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call # your external grep (e.g., if your system lacks grep, if its grep is # broken, or spawning external process is slower than built-in grep git has). +# +# Define USE_NED_ALLOCATOR if you want to replace the platforms default +# memory allocators with the nedmalloc allocator written by Niall Douglas. GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -827,6 +830,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_NSEC = YesPlease USE_WIN32_MMAP = YesPlease + USE_NED_ALLOCATOR = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o @@ -1106,6 +1110,11 @@ ifdef NO_EXTERNAL_GREP BASIC_CFLAGS += -DNO_EXTERNAL_GREP endif +ifdef USE_NED_ALLOCATOR + COMPAT_CFLAGS += -DUSE_NED_ALLOCATOR -DOVERRIDE_STRDUP -DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR -Icompat/nedmalloc + COMPAT_OBJS += compat/nedmalloc/nedmalloc.o +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif diff --git a/compat/nedmalloc/License.txt b/compat/nedmalloc/License.txt new file mode 100644 index 0000000000..36b7cd93cd --- /dev/null +++ b/compat/nedmalloc/License.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/compat/nedmalloc/Readme.txt b/compat/nedmalloc/Readme.txt new file mode 100644 index 0000000000..0534be7c20 --- /dev/null +++ b/compat/nedmalloc/Readme.txt @@ -0,0 +1,136 @@ +nedalloc v1.05 15th June 2008: +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +by Niall Douglas (http://www.nedprod.com/programs/portable/nedmalloc/) + +Enclosed is nedalloc, an alternative malloc implementation for multiple +threads without lock contention based on dlmalloc v2.8.4. It is more +or less a newer implementation of ptmalloc2, the standard allocator in +Linux (which is based on dlmalloc v2.7.0) but also contains a per-thread +cache for maximum CPU scalability. + +It is licensed under the Boost Software License which basically means +you can do anything you like with it. This does not apply to the malloc.c.h +file which remains copyright to others. + +It has been tested on win32 (x86), win64 (x64), Linux (x64), FreeBSD (x64) +and Apple MacOS X (x86). It works very well on all of these and is very +significantly faster than the system allocator on all of these platforms. + +By literally dropping in this allocator as a replacement for your system +allocator, you can see real world improvements of up to three times in normal +code! + +To use: +-=-=-=- +Drop in nedmalloc.h, nedmalloc.c and malloc.c.h into your project. +Configure using the instructions in nedmalloc.h. Run and enjoy. + +To test, compile test.c. It will run a comparison between your system +allocator and nedalloc and tell you how much faster nedalloc is. It also +serves as an example of usage. + +Notes: +-=-=-= +If you want the very latest version of this allocator, get it from the +TnFOX SVN repository at svn://svn.berlios.de/viewcvs/tnfox/trunk/src/nedmalloc + +Because of how nedalloc allocates an mspace per thread, it can cause +severe bloating of memory usage under certain allocation patterns. +You can substantially reduce this wastage by setting MAXTHREADSINPOOL +or the threads parameter to nedcreatepool() to a fraction of the number of +threads which would normally be in a pool at once. This will reduce +bloating at the cost of an increase in lock contention. If allocated size +is less than THREADCACHEMAX, locking is avoided 90-99% of the time and +if most of your allocations are below this value, you can safely set +MAXTHREADSINPOOL to one. + +You will suffer memory leakage unless you call neddisablethreadcache() +per pool for every thread which exits. This is because nedalloc cannot +portably know when a thread exits and thus when its thread cache can +be returned for use by other code. Don't forget pool zero, the system pool. + +For C++ type allocation patterns (where the same sizes of memory are +regularly allocated and deallocated as objects are created and destroyed), +the threadcache always benefits performance. If however your allocation +patterns are different, searching the threadcache may significantly slow +down your code - as a rule of thumb, if cache utilisation is below 80% +(see the source for neddisablethreadcache() for how to enable debug +printing in release mode) then you should disable the thread cache for +that thread. You can compile out the threadcache code by setting +THREADCACHEMAX to zero. + +Speed comparisons: +-=-=-=-=-=-=-=-=-= +See Benchmarks.xls for details. + +The enclosed test.c can do two things: it can be a torture test or a speed +test. The speed test is designed to be a representative synthetic +memory allocator test. It works by randomly mixing allocations with frees +with half of the allocation sizes being a two power multiple less than +512 bytes (to mimic C++ stack instantiated objects) and the other half +being a simple random value less than 16Kb. + +The real world code results are from Tn's TestIO benchmark. This is a +heavily multithreaded and memory intensive benchmark with a lot of branching +and other stuff modern processors don't like so much. As you'll note, the +test doesn't show the benefits of the threadcache mostly due to the saturation +of the memory bus being the limiting factor. + +ChangeLog: +-=-=-=-=-= +v1.05 15th June 2008: + * { 1042 } Added error check for TLSSET() and TLSFREE() macros. Thanks to +Markus Elfring for reporting this. + * { 1043 } Fixed a segfault when freeing memory allocated using +nedindependent_comalloc(). Thanks to Pavel Vozenilek for reporting this. + +v1.04 14th July 2007: + * Fixed a bug with the new optimised implementation that failed to lock +on a realloc under certain conditions. + * Fixed lack of thread synchronisation in InitPool() causing pool corruption + * Fixed a memory leak of thread cache contents on disabling. Thanks to Earl +Chew for reporting this. + * Added a sanity check for freed blocks being valid. + * Reworked test.c into being a torture test. + * Fixed GCC assembler optimisation misspecification + +v1.04alpha_svn915 7th October 2006: + * Fixed failure to unlock thread cache list if allocating a new list failed. +Thanks to Dmitry Chichkov for reporting this. Futher thanks to Aleksey Sanin. + * Fixed realloc(0, ) segfaulting. Thanks to Dmitry Chichkov for +reporting this. + * Made config defines #ifndef so they can be overriden by the build system. +Thanks to Aleksey Sanin for suggesting this. + * Fixed deadlock in nedprealloc() due to unnecessary locking of preferred +thread mspace when mspace_realloc() always uses the original block's mspace +anyway. Thanks to Aleksey Sanin for reporting this. + * Made some speed improvements by hacking mspace_malloc() to no longer lock +its mspace, thus allowing the recursive mutex implementation to be removed +with an associated speed increase. Thanks to Aleksey Sanin for suggesting this. + * Fixed a bug where allocating mspaces overran its max limit. Thanks to +Aleksey Sanin for reporting this. + +v1.03 10th July 2006: + * Fixed memory corruption bug in threadcache code which only appeared with >4 +threads and in heavy use of the threadcache. + +v1.02 15th May 2006: + * Integrated dlmalloc v2.8.4, fixing the win32 memory release problem and +improving performance still further. Speed is now up to twice the speed of v1.01 +(average is 67% faster). + * Fixed win32 critical section implementation. Thanks to Pavel Kuznetsov +for reporting this. + * Wasn't locking mspace if all mspaces were locked. Thanks to Pavel Kuznetsov +for reporting this. + * Added Apple Mac OS X support. + +v1.01 24th February 2006: + * Fixed multiprocessor scaling problems by removing sources of cache sloshing + * Earl Chew agilent com> sent patches for the following: + 1. size2binidx() wasn't working for default code path (non x86) + 2. Fixed failure to release mspace lock under certain circumstances which + caused a deadlock + +v1.00 1st January 2006: + * First release diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h new file mode 100644 index 0000000000..1d9bbe0aba --- /dev/null +++ b/compat/nedmalloc/malloc.c.h @@ -0,0 +1,5750 @@ +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain, as explained at + http://creativecommons.org/licenses/publicdomain. Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* Version pre-2.8.4 Mon Nov 27 11:22:37 2006 (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O3), and link it into another program. All of + the compile-time options default to reasonable values for use on + most platforms. You might later want to step through various + compile-time and dynamic tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.4.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. Note that you may already by default be using a C + library containing a malloc that is based on some version of this + malloc (for example in linux). You might still want to use the one + in this file to customize settings or to avoid overheads associated + with library versions. + +* Vital statistics: + + Supported pointer/size_t representation: 4 or 8 bytes + size_t MUST be an unsigned type of the same width as + pointers. (If you are using an ancient system that declares + size_t as a signed type, or need it to be a different width + than pointers, you can use a previous release of this malloc + (e.g. 2.7.2) supporting these.) + + Alignment: 8 bytes (default) + This suffices for nearly all current machines and C compilers. + However, you can define MALLOC_ALIGNMENT to be wider than this + if necessary (up to 128bytes), at the expense of using more space. + + Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) + 8 or 16 bytes (if 8byte sizes) + Each malloced chunk has a hidden word of overhead holding size + and status information, and additional cross-check word + if FOOTERS is defined. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) + 8-byte ptrs: 32 bytes (including overhead) + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is about + 32 bytes plus the remainder from a system page (the minimal + mmap unit); typically 4096 or 8192 bytes. + + Security: static-safe; optionally more or less + The "security" of malloc refers to the ability of malicious + code to accentuate the effects of errors (for example, freeing + space that is not currently malloc'ed or overwriting past the + ends of chunks) in code that calls malloc. This malloc + guarantees not to modify any memory locations below the base of + heap, i.e., static variables, even in the presence of usage + errors. The routines additionally detect most improper frees + and reallocs. All this holds as long as the static bookkeeping + for malloc itself is not corrupted by some other means. This + is only one aspect of security -- these checks do not, and + cannot, detect all possible programming errors. + + If FOOTERS is defined nonzero, then each allocated chunk + carries an additional check word to verify that it was malloced + from its space. These check words are the same within each + execution of a program using malloc, but differ across + executions, so externally crafted fake chunks cannot be + freed. This improves security by rejecting frees/reallocs that + could corrupt heap memory, in addition to the checks preventing + writes to statics that are always on. This may further improve + security at the expense of time and space overhead. (Note that + FOOTERS may also be worth using with MSPACES.) + + By default detected errors cause the program to abort (calling + "abort()"). You can override this to instead proceed past + errors by defining PROCEED_ON_ERROR. In this case, a bad free + has no effect, and a malloc that encounters a bad address + caused by user overwrites will ignore the bad address by + dropping pointers and indices to all known memory. This may + be appropriate for programs that should continue if at all + possible in the face of programming errors, although they may + run out of memory because dropped memory is never reclaimed. + + If you don't like either of these options, you can define + CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything + else. And if if you are sure that your program using malloc has + no errors or vulnerabilities, you can define INSECURE to 1, + which might (or might not) provide a small performance improvement. + + Thread-safety: NOT thread-safe unless USE_LOCKS defined + When USE_LOCKS is defined, each public call to malloc, free, + etc is surrounded with either a pthread mutex or a win32 + spinlock (depending on WIN32). This is not especially fast, and + can be a major bottleneck. It is designed only to provide + minimal protection in concurrent environments, and to provide a + basis for extensions. If you are using malloc in a concurrent + program, consider instead using nedmalloc + (http://www.nedprod.com/programs/portable/nedmalloc/) or + ptmalloc (See http://www.malloc.de), which are derived + from versions of this malloc. + + System requirements: Any combination of MORECORE and/or MMAP/MUNMAP + This malloc can use unix sbrk or any emulation (invoked using + the CALL_MORECORE macro) and/or mmap/munmap or any emulation + (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system + memory. On most unix systems, it tends to work best if both + MORECORE and MMAP are enabled. On Win32, it uses emulations + based on VirtualAlloc. It also uses common C library functions + like memset. + + Compliance: I believe it is compliant with the Single Unix Specification + (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Overview of algorithms + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and + tunable. Consistent balance across these factors results in a good + general-purpose allocator for malloc-intensive programs. + + In most ways, this malloc is a best-fit allocator. Generally, it + chooses the best-fitting existing chunk for a request, with ties + broken in approximately least-recently-used order. (This strategy + normally maintains low fragmentation.) However, for requests less + than 256bytes, it deviates from best-fit when there is not an + exactly fitting available chunk by preferring to use space adjacent + to that used for the previous small request, as well as by breaking + ties in approximately most-recently-used order. (These enhance + locality of series of small allocations.) And for very large requests + (>= 256Kb by default), it relies on system memory mapping + facilities, if supported. (This helps avoid carrying around and + possibly fragmenting memory used only for large chunks.) + + All operations (except malloc_stats and mallinfo) have execution + times that are bounded by a constant factor of the number of bits in + a size_t, not counting any clearing in calloc or copying in realloc, + or actions surrounding MORECORE and MMAP that have times + proportional to the number of non-contiguous regions returned by + system allocation routines, which is often just 1. In real-time + applications, you can optionally suppress segment traversals using + NO_SEGMENT_TRAVERSAL, which assures bounded execution even when + system allocators return non-contiguous spaces, at the typical + expense of carrying around more memory and increased fragmentation. + + The implementation is not very modular and seriously overuses + macros. Perhaps someday all C compilers will do as good a job + inlining modular code as can now be done by brute-force expansion, + but now, enough of them seem not to. + + Some compilers issue a lot of warnings about code that is + dead/unreachable only on some platforms, and also about intentional + uses of negation on unsigned types. All known cases of each can be + ignored. + + For a longer but out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + +* MSPACES + If MSPACES is defined, then in addition to malloc, free, etc., + this file also defines mspace_malloc, mspace_free, etc. These + are versions of malloc routines that take an "mspace" argument + obtained using create_mspace, to control all internal bookkeeping. + If ONLY_MSPACES is defined, only these versions are compiled. + So if you would like to use this allocator for only some allocations, + and your system malloc for others, you can compile with + ONLY_MSPACES and then do something like... + static mspace mymspace = create_mspace(0,0); // for example + #define mymalloc(bytes) mspace_malloc(mymspace, bytes) + + (Note: If you only need one instance of an mspace, you can instead + use "USE_DL_PREFIX" to relabel the global malloc.) + + You can similarly create thread-local allocators by storing + mspaces as thread-locals. For example: + static __thread mspace tlms = 0; + void* tlmalloc(size_t bytes) { + if (tlms == 0) tlms = create_mspace(0, 0); + return mspace_malloc(tlms, bytes); + } + void tlfree(void* mem) { mspace_free(tlms, mem); } + + Unless FOOTERS is defined, each mspace is completely independent. + You cannot allocate from one and free to another (although + conformance is only weakly checked, so usage errors are not always + caught). If FOOTERS is defined, then each chunk carries around a tag + indicating its originating mspace, and frees are directed to their + originating spaces. + + ------------------------- Compile-time options --------------------------- + +Be careful in setting #define values for numerical constants of type +size_t. On some systems, literal values are not automatically extended +to size_t precision unless they are explicitly casted. You can also +use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below. + +WIN32 default: defined if _WIN32 defined + Defining WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. Beware that there seem to be some + cases where this malloc might not be a pure drop-in replacement for + Win32 malloc: Random-looking failures from Win32 GDI API's (eg; + SetDIBits()) may be due to bugs in some video driver implementations + when pixel buffers are malloc()ed, and the region spans more than + one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb) + default granularity, pixel buffers may straddle virtual allocation + regions more often than when using the Microsoft allocator. You can + avoid this by using VirtualAlloc() and VirtualFree() for all pixel + buffers rather than using malloc(). If this is not possible, + recompile this malloc with a larger DEFAULT_GRANULARITY. + +MALLOC_ALIGNMENT default: (size_t)8 + Controls the minimum alignment for malloc'ed chunks. It must be a + power of two and at least 8, even on machines for which smaller + alignments would suffice. It may be defined as larger than this + though. Note however that code and data structures are optimized for + the case of 8-byte alignment. + +MSPACES default: 0 (false) + If true, compile in support for independent allocation spaces. + This is only supported if HAVE_MMAP is true. + +ONLY_MSPACES default: 0 (false) + If true, only compile in mspace versions, not regular versions. + +USE_LOCKS default: 0 (false) + Causes each call to each public routine to be surrounded with + pthread or WIN32 mutex lock/unlock. (If set true, this can be + overridden on a per-mspace basis for mspace versions.) If set to a + non-zero value other than 1, locks are used, but their + implementation is left out, so lock functions must be supplied manually. + +USE_SPIN_LOCKS default: 1 iff USE_LOCKS and on x86 using gcc or MSC + If true, uses custom spin locks for locking. This is currently + supported only for x86 platforms using gcc or recent MS compilers. + Otherwise, posix locks or win32 critical sections are used. + +FOOTERS default: 0 + If true, provide extra checking and dispatching by placing + information in the footers of allocated chunks. This adds + space and time overhead. + +INSECURE default: 0 + If true, omit checks for usage errors and heap space overwrites. + +USE_DL_PREFIX default: NOT defined + Causes compiler to prefix all public routines with the string 'dl'. + This can be useful when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. + +ABORT default: defined as abort() + Defines how to abort on failed checks. On most systems, a failed + check cannot die with an "assert" or even print an informative + message, because the underlying print routines in turn call malloc, + which will fail again. Generally, the best policy is to simply call + abort(). It's not very useful to do more than this because many + errors due to overwriting will show up as address faults (null, odd + addresses etc) rather than malloc-triggered checks, so will also + abort. Also, most compilers know that abort() does not return, so + can better optimize code conditionally calling it. + +PROCEED_ON_ERROR default: defined as 0 (false) + Controls whether detected bad addresses cause them to bypassed + rather than aborting. If set, detected bad arguments to free and + realloc are ignored. And all bookkeeping information is zeroed out + upon a detected overwrite of freed heap space, thus losing the + ability to ever return it from malloc again, but enabling the + application to proceed. If PROCEED_ON_ERROR is defined, the + static variable malloc_corruption_error_count is compiled in + and can be examined to see if errors have occurred. This option + generates slower code than the default abort policy. + +DEBUG default: NOT defined + The DEBUG setting is mainly intended for people trying to modify + this code or diagnose problems when porting to new platforms. + However, it may also be able to better isolate user errors than just + using runtime checks. The assertions in the check routines spell + out in more detail the assumptions and invariants underlying the + algorithms. The checking is fairly extensive, and will slow down + execution noticeably. Calling malloc_stats or mallinfo with DEBUG + set will attempt to check every non-mmapped allocated and free chunk + in the course of computing the summaries. + +ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) + Debugging assertion failures can be nearly impossible if your + version of the assert macro causes malloc to be called, which will + lead to a cascade of further failures, blowing the runtime stack. + ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), + which will usually make debugging easier. + +MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 + The action to take before "return 0" when malloc fails to be able to + return memory because there is none available. + +HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES + True if this system supports sbrk or an emulation of it. + +MORECORE default: sbrk + The name of the sbrk-style system routine to call to obtain more + memory. See below for guidance on writing custom MORECORE + functions. The type of the argument to sbrk/MORECORE varies across + systems. It cannot be size_t, because it supports negative + arguments, so it is normally the signed type of the same width as + size_t (sometimes declared as "intptr_t"). It doesn't much matter + though. Internally, we only call it with arguments less than half + the max value of a size_t, which should work across all reasonable + possibilities, although sometimes generating compiler warnings. + +MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE + If true, take advantage of fact that consecutive calls to MORECORE + with positive arguments always return contiguous increasing + addresses. This is true of unix sbrk. It does not hurt too much to + set it true anyway, since malloc copes with non-contiguities. + Setting it false when definitely non-contiguous saves time + and possibly wasted space it would take to discover this though. + +MORECORE_CANNOT_TRIM default: NOT defined + True if MORECORE cannot release space back to the system when given + negative arguments. This is generally necessary only if you are + using a hand-crafted MORECORE function that cannot handle negative + arguments. + +NO_SEGMENT_TRAVERSAL default: 0 + If non-zero, suppresses traversals of memory segments + returned by either MORECORE or CALL_MMAP. This disables + merging of segments that are contiguous, and selectively + releasing them to the OS if unused, but bounds execution times. + +HAVE_MMAP default: 1 (true) + True if this system supports mmap or an emulation of it. If so, and + HAVE_MORECORE is not true, MMAP is used for all system + allocation. If set and HAVE_MORECORE is true as well, MMAP is + primarily used to directly allocate very large blocks. It is also + used as a backup strategy in cases where MORECORE fails to provide + space from system. Note: A single call to MUNMAP is assumed to be + able to unmap memory that may have be allocated using multiple calls + to MMAP, so long as they are adjacent. + +HAVE_MREMAP default: 1 on linux, else 0 + If true realloc() uses mremap() to re-allocate large blocks and + extend or shrink allocation spaces. + +MMAP_CLEARS default: 1 except on WINCE. + True if mmap clears memory so calloc doesn't need to. This is true + for standard unix mmap using /dev/zero and on WIN32 except for WINCE. + +USE_BUILTIN_FFS default: 0 (i.e., not used) + Causes malloc to use the builtin ffs() function to compute indices. + Some compilers may recognize and intrinsify ffs to be faster than the + supplied C version. Also, the case of x86 using gcc is special-cased + to an asm instruction, so is already as fast as it can be, and so + this setting has no effect. Similarly for Win32 under recent MS compilers. + (On most x86s, the asm version is only slightly faster than the C version.) + +malloc_getpagesize default: derive from system includes, or 4096. + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. This may be (and + usually is) a function rather than a constant. This is ignored + if WIN32, where page size is determined using getSystemInfo during + initialization. + +USE_DEV_RANDOM default: 0 (i.e., not used) + Causes malloc to use /dev/random to initialize secure magic seed for + stamping footers. Otherwise, the current time is used. + +NO_MALLINFO default: 0 + If defined, don't compile "mallinfo". This can be a simple way + of dealing with mismatches between system declarations and + those in this file. + +MALLINFO_FIELD_TYPE default: size_t + The type of the fields in the mallinfo struct. This was originally + defined as "int" in SVID etc, but is more usefully defined as + size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set + +REALLOC_ZERO_BYTES_FREES default: not defined + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does + realloc(p, 0). + +LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H +LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H +LACKS_STDLIB_H default: NOT defined unless on WIN32 + Define these if your system does not have these header files. + You might need to manually insert some of the declarations they provide. + +DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, + system_info.dwAllocationGranularity in WIN32, + otherwise 64K. + Also settable using mallopt(M_GRANULARITY, x) + The unit for allocating and deallocating memory from the system. On + most systems with contiguous MORECORE, there is no reason to + make this more than a page. However, systems with MMAP tend to + either require or encourage larger granularities. You can increase + this value to prevent system allocation functions to be called so + often, especially if they are slow. The value must be at least one + page and must be a power of two. Setting to 0 causes initialization + to either page size or win32 region size. (Note: In previous + versions of malloc, the equivalent of this option was called + "TOP_PAD") + +DEFAULT_TRIM_THRESHOLD default: 2MB + Also settable using mallopt(M_TRIM_THRESHOLD, x) + The maximum amount of unused top-most memory to keep before + releasing via malloc_trim in free(). Automatic trimming is mainly + useful in long-lived programs using contiguous MORECORE. Because + trimming via sbrk can be slow on some systems, and can sometimes be + wasteful (in cases where programs immediately afterward allocate + more large chunks) the value should be high enough so that your + overall system performance would improve by releasing this much + memory. As a rough guide, you might set to a value close to the + average size of a process (program) running on your system. + Releasing this much memory would allow such a process to run in + memory. Generally, it is worth tuning trim thresholds when a + program undergoes phases where several large chunks are allocated + and released in ways that can reuse each other's storage, perhaps + mixed with phases where there are no such chunks at all. The trim + value must be greater than page size to have any useful effect. To + disable trimming completely, you can set to MAX_SIZE_T. Note that the trick + some people use of mallocing a huge space and then freeing it at + program startup, in an attempt to reserve system memory, doesn't + have the intended effect under automatic trimming, since that memory + will immediately be returned to the system. + +DEFAULT_MMAP_THRESHOLD default: 256K + Also settable using mallopt(M_MMAP_THRESHOLD, x) + The request size threshold for using MMAP to directly service a + request. Requests of at least this size that cannot be allocated + using already-existing space will be serviced via mmap. (If enough + normal freed space already exists it is used instead.) Using mmap + segregates relatively large chunks of memory so that they can be + individually obtained and released from the host system. A request + serviced through mmap is never reused by any other request (at least + not directly; the system may just so happen to remap successive + requests to the same locations). Segregating space in this way has + the benefits that: Mmapped space can always be individually released + back to the system, which helps keep the system level memory demands + of a long-lived program low. Also, mapped memory doesn't become + `locked' between other chunks, as can happen with normally allocated + chunks, which means that even trimming via malloc_trim would not + release them. However, it has the disadvantage that the space + cannot be reclaimed, consolidated, and then used to service later + requests, as happens with normal chunks. The advantages of mmap + nearly always outweigh disadvantages for "large" chunks, but the + value of "large" may vary across systems. The default is an + empirically derived value that works well in most systems. You can + disable mmap by setting to MAX_SIZE_T. + +MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP + The number of consolidated frees between checks to release + unused segments when freeing. When using non-contiguous segments, + especially with multiple mspaces, checking only for topmost space + doesn't always suffice to trigger trimming. To compensate for this, + free() will, with a period of MAX_RELEASE_CHECK_RATE (or the + current number of segments, if greater) try to release unused + segments to the OS when freeing chunks that result in + consolidation. The best value for this parameter is a compromise + between slowing down frees with relatively costly checks that + rarely trigger versus holding on to unused memory. To effectively + disable, set to MAX_SIZE_T. This may lead to a very slight speed + improvement at the expense of carrying around more memory. +*/ + +/* Version identifier to allow people to support multiple versions */ +#ifndef DLMALLOC_VERSION +#define DLMALLOC_VERSION 20804 +#endif /* DLMALLOC_VERSION */ + +#ifndef WIN32 +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#ifdef _WIN32_WCE +#define LACKS_FCNTL_H +#define WIN32 1 +#endif /* _WIN32_WCE */ +#endif /* WIN32 */ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x403 +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION +#endif /* MALLOC_FAILURE_ACTION */ +#ifdef _WIN32_WCE /* WINCE reportedly does not clear */ +#define MMAP_CLEARS 0 +#else +#define MMAP_CLEARS 1 +#endif /* _WIN32_WCE */ +#endif /* WIN32 */ + +#if defined(DARWIN) || defined(_DARWIN) +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +/* OSX allocators provide 16 byte alignment */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)16U) +#endif +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ + +#ifndef LACKS_SYS_TYPES_H +#include /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef ONLY_MSPACES +#define ONLY_MSPACES 0 /* define to a value */ +#else +#define ONLY_MSPACES 1 +#endif /* ONLY_MSPACES */ +#ifndef MSPACES +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)8U) +#endif /* MALLOC_ALIGNMENT */ +#ifndef FOOTERS +#define FOOTERS 0 +#endif /* FOOTERS */ +#ifndef ABORT +#define ABORT abort() +#endif /* ABORT */ +#ifndef ABORT_ON_ASSERT_FAILURE +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ +#ifndef PROCEED_ON_ERROR +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ +#ifndef USE_LOCKS +#define USE_LOCKS 0 +#endif /* USE_LOCKS */ +#ifndef USE_SPIN_LOCKS +#if USE_LOCKS && (defined(__GNUC__) && ((defined(__i386__) || defined(__x86_64__)))) || (defined(_MSC_VER) && _MSC_VER>=1310) +#define USE_SPIN_LOCKS 1 +#else +#define USE_SPIN_LOCKS 0 +#endif /* USE_LOCKS && ... */ +#endif /* USE_SPIN_LOCKS */ +#ifndef INSECURE +#define INSECURE 0 +#endif /* INSECURE */ +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef HAVE_MORECORE +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ +#if !HAVE_MORECORE +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#define MORECORE_DEFAULT sbrk +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ +#ifndef DEFAULT_GRANULARITY +#if (MORECORE_CONTIGUOUS || defined(WIN32)) +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ +#ifndef DEFAULT_TRIM_THRESHOLD +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef DEFAULT_MMAP_THRESHOLD +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ +#ifndef MAX_RELEASE_CHECK_RATE +#if HAVE_MMAP +#define MAX_RELEASE_CHECK_RATE 4095 +#else +#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* MAX_RELEASE_CHECK_RATE */ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ +#ifndef USE_DEV_RANDOM +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ +#ifndef NO_SEGMENT_TRAVERSAL +#define NO_SEGMENT_TRAVERSAL 0 +#endif /* NO_SEGMENT_TRAVERSAL */ + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +/* ------------------------ Mallinfo declarations ------------------------ */ + +#if !NO_MALLINFO +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any system that has a + /usr/include/malloc.h defining struct mallinfo. The main + declaration needed is the mallinfo struct that is returned (by-copy) + by mallinfo(). The malloinfo struct contains a bunch of fields that + are not even meaningful in this version of malloc. These fields are + are instead filled by mallinfo() with other numbers that might be of + interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else a compliant version is + declared below. These must be precisely the same for mallinfo() to + work. The original SVID version of this struct, defined on most + systems with mallinfo, declares all fields as ints. But some others + define as unsigned long. If your system defines the fields using a + type of different width than listed here, you MUST #include your + system version and #define HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ +#ifndef STRUCT_MALLINFO_DECLARED +#define STRUCT_MALLINFO_DECLARED 1 +struct mallinfo { + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ +}; +#endif /* STRUCT_MALLINFO_DECLARED */ +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ + +/* + Try to persuade compilers to inline. The most critical functions for + inlining are defined as macros, so these aren't used for them. +*/ + +#ifndef FORCEINLINE + #if defined(__GNUC__) +#define FORCEINLINE __inline __attribute__ ((always_inline)) + #elif defined(_MSC_VER) + #define FORCEINLINE __forceinline + #endif +#endif +#ifndef NOINLINE + #if defined(__GNUC__) + #define NOINLINE __attribute__ ((noinline)) + #elif defined(_MSC_VER) + #define NOINLINE __declspec(noinline) + #else + #define NOINLINE + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#ifndef FORCEINLINE + #define FORCEINLINE inline +#endif +#endif /* __cplusplus */ +#ifndef FORCEINLINE + #define FORCEINLINE +#endif + +#if !ONLY_MSPACES + +/* ------------------- Declarations of public routines ------------------- */ + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlrealloc realloc +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#endif /* USE_DL_PREFIX */ + + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +void* dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cause the current program to abort. +*/ +void dlfree(void*); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +void* dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ + +void* dlrealloc(void*, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +void* dlmemalign(size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +void* dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. To workaround the fact that mallopt is specified to use int, + not size_t parameters, the value -1 is specially treated as the + maximum unsigned size_t value. + + SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +int dlmallopt(int, int); + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +size_t dlmalloc_footprint(void); + +/* + malloc_max_footprint(); + Returns the maximum number of bytes obtained from the system. This + value will be greater than current footprint if deallocated space + has been reclaimed by the system. The peak number of bytes allocated + by malloc, realloc etc., is less than this value. Unlike mallinfo, + this function returns only a precomputed result, so can be called + frequently to monitor memory consumption. Even if locks are + otherwise defined, this function does not use them, so results might + not be up to date. +*/ +size_t dlmalloc_max_footprint(void); + +#if !NO_MALLINFO +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: always zero. + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: always zero + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +struct mallinfo dlmallinfo(void); +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use regular calloc and assign pointers into this + space to represent elements. (In this case though, you cannot + independently free elements.) + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +void** dlindependent_calloc(size_t, size_t, void**); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use a single regular malloc, and assign pointers at + particular offsets in the aggregate space. (In this case though, you + cannot independently free elements.) + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +void** dlindependent_comalloc(size_t, size_t*, void**); + + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +void* dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +int dlmalloc_trim(size_t); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +void dlmalloc_stats(void); + +#endif /* ONLY_MSPACES */ + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void*); + + +#if MSPACES + +/* + mspace is an opaque type representing an independent + region of space that supports mspace_malloc, etc. +*/ +typedef void* mspace; + +/* + create_mspace creates and returns a new independent space with the + given initial capacity, or, if 0, the default granularity size. It + returns null if there is no system memory available to create the + space. If argument locked is non-zero, the space uses a separate + lock to control access. The capacity of the space will grow + dynamically as needed to service mspace_malloc requests. You can + control the sizes of incremental increases of this space by + compiling with a different DEFAULT_GRANULARITY or dynamically + setting with mallopt(M_GRANULARITY, value). +*/ +mspace create_mspace(size_t capacity, int locked); + +/* + destroy_mspace destroys the given space, and attempts to return all + of its memory back to the system, returning the total number of + bytes freed. After destruction, the results of access to all memory + used by the space become undefined. +*/ +size_t destroy_mspace(mspace msp); + +/* + create_mspace_with_base uses the memory supplied as the initial base + of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this + space is used for bookkeeping, so the capacity must be at least this + large. (Otherwise 0 is returned.) When this initial space is + exhausted, additional memory will be obtained from the system. + Destroying this space will deallocate all additionally allocated + space (if possible) but not the initial base. +*/ +mspace create_mspace_with_base(void* base, size_t capacity, int locked); + +/* + mspace_mmap_large_chunks controls whether requests for large chunks + are allocated in their own mmapped regions, separate from others in + this mspace. By default this is enabled, which reduces + fragmentation. However, such chunks are not necessarily released to + the system upon destroy_mspace. Disabling by setting to false may + increase fragmentation, but avoids leakage when relying on + destroy_mspace to release all memory allocated using this space. +*/ +int mspace_mmap_large_chunks(mspace msp, int enable); + + +/* + mspace_malloc behaves as malloc, but operates within + the given space. +*/ +void* mspace_malloc(mspace msp, size_t bytes); + +/* + mspace_free behaves as free, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_free is not actually needed. + free may be called instead of mspace_free because freed chunks from + any space are handled by their originating spaces. +*/ +void mspace_free(mspace msp, void* mem); + +/* + mspace_realloc behaves as realloc, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_realloc is not actually + needed. realloc may be called instead of mspace_realloc because + realloced chunks from any space are handled by their originating + spaces. +*/ +void* mspace_realloc(mspace msp, void* mem, size_t newsize); + +/* + mspace_calloc behaves as calloc, but operates within + the given space. +*/ +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); + +/* + mspace_memalign behaves as memalign, but operates within + the given space. +*/ +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); + +/* + mspace_independent_calloc behaves as independent_calloc, but + operates within the given space. +*/ +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]); + +/* + mspace_independent_comalloc behaves as independent_comalloc, but + operates within the given space. +*/ +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]); + +/* + mspace_footprint() returns the number of bytes obtained from the + system for this space. +*/ +size_t mspace_footprint(mspace msp); + +/* + mspace_max_footprint() returns the peak number of bytes obtained from the + system for this space. +*/ +size_t mspace_max_footprint(mspace msp); + + +#if !NO_MALLINFO +/* + mspace_mallinfo behaves as mallinfo, but reports properties of + the given space. +*/ +struct mallinfo mspace_mallinfo(mspace msp); +#endif /* NO_MALLINFO */ + +/* + malloc_usable_size(void* p) behaves the same as malloc_usable_size; +*/ + size_t mspace_usable_size(void* mem); + +/* + mspace_malloc_stats behaves as malloc_stats, but reports + properties of the given space. +*/ +void mspace_malloc_stats(mspace msp); + +/* + mspace_trim behaves as malloc_trim, but + operates within the given space. +*/ +int mspace_trim(mspace msp, size_t pad); + +/* + An alias for mallopt. +*/ +int mspace_mallopt(int, int); + +#endif /* MSPACES */ + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif /* __cplusplus */ + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/*------------------------------ internal #includes ---------------------- */ + +#ifdef WIN32 +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* WIN32 */ + +#include /* for printing in malloc_stats */ + +#ifndef LACKS_ERRNO_H +#include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ +#if FOOTERS +#include /* for magic initialization */ +#endif /* FOOTERS */ +#ifndef LACKS_STDLIB_H +#include /* for abort() */ +#endif /* LACKS_STDLIB_H */ +#ifdef DEBUG +#if ABORT_ON_ASSERT_FAILURE +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#ifndef assert +#define assert(x) +#endif +#define DEBUG 0 +#endif /* DEBUG */ +#ifndef LACKS_STRING_H +#include /* for memset etc */ +#endif /* LACKS_STRING_H */ +#if USE_BUILTIN_FFS +#ifndef LACKS_STRINGS_H +#include /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ +#if HAVE_MMAP +#ifndef LACKS_SYS_MMAN_H +#include /* for mmap */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ +#ifndef LACKS_UNISTD_H +#include /* for sbrk, sysconf */ +#else /* LACKS_UNISTD_H */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +extern void* sbrk(ptrdiff_t); +#endif /* FreeBSD etc */ +#endif /* LACKS_UNISTD_H */ + +/* Declarations for locking */ +#if USE_LOCKS +#ifndef WIN32 +#include +#if defined (__SVR4) && defined (__sun) /* solaris */ +#include +#endif /* solaris */ +#else +#ifndef _M_AMD64 +/* These are already defined on AMD64 builds */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +#ifndef __MINGW32__ +LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp); +LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); +#endif +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _M_AMD64 */ +#ifndef __MINGW32__ +#pragma intrinsic (_InterlockedCompareExchange) +#pragma intrinsic (_InterlockedExchange) +#else + /* --[ start GCC compatibility ]---------------------------------------------- + * Compatibility header for GCC -- GCC equivalents of intrinsic + * Microsoft Visual C++ functions. Originally developed for the ReactOS + * () and TinyKrnl () + * projects. + * + * Copyright (c) 2006 KJK::Hyperion + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + /*** Atomic operations ***/ + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 + #define _ReadWriteBarrier() __sync_synchronize() + #else + static __inline__ __attribute__((always_inline)) long __sync_lock_test_and_set(volatile long * const Target, const long Value) + { + long res; + __asm__ __volatile__("xchg%z0 %2, %0" : "=g" (*(Target)), "=r" (res) : "1" (Value)); + return res; + } + static void __inline__ __attribute__((always_inline)) _MemoryBarrier(void) + { + __asm__ __volatile__("" : : : "memory"); + } + #define _ReadWriteBarrier() _MemoryBarrier() + #endif + /* BUGBUG: GCC only supports full barriers */ + static __inline__ __attribute__((always_inline)) long _InterlockedExchange(volatile long * const Target, const long Value) + { + /* NOTE: __sync_lock_test_and_set would be an acquire barrier, so we force a full barrier */ + _ReadWriteBarrier(); + return __sync_lock_test_and_set(Target, Value); + } + /* --[ end GCC compatibility ]---------------------------------------------- */ +#endif +#define interlockedcompareexchange _InterlockedCompareExchange +#define interlockedexchange _InterlockedExchange +#endif /* Win32 */ +#endif /* USE_LOCKS */ + +/* Declarations for bit scanning on win32 */ +#if defined(_MSC_VER) && _MSC_VER>=1300 +#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse) +#endif /* BitScanForward */ +#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */ + +#ifndef WIN32 +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize ((size_t)4096U) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif +#endif + + + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some platforms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define SIZE_T_FOUR ((size_t)4) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ + +#if HAVE_MMAP + +#ifndef WIN32 +#define MUNMAP_DEFAULT(a, s) munmap((a), (s)) +#define MMAP_PROT (PROT_READ|PROT_WRITE) +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif /* MAP_ANON */ +#ifdef MAP_ANONYMOUS +#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) +#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) +#else /* MAP_ANONYMOUS */ +/* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. +*/ +#define MMAP_FLAGS (MAP_PRIVATE) +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ +#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) +#endif /* MAP_ANONYMOUS */ + +#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) + +#else /* WIN32 */ + +/* Win32 MMAP via VirtualAlloc */ +static FORCEINLINE void* win32mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ +static FORCEINLINE void* win32direct_mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, + PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* This function supports releasing coalesed segments */ +static FORCEINLINE int win32munmap(void* ptr, size_t size) { + MEMORY_BASIC_INFORMATION minfo; + char* cptr = (char*)ptr; + while (size) { + if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) + return -1; + if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || + minfo.State != MEM_COMMIT || minfo.RegionSize > size) + return -1; + if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) + return -1; + cptr += minfo.RegionSize; + size -= minfo.RegionSize; + } + return 0; +} + +#define MMAP_DEFAULT(s) win32mmap(s) +#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MREMAP +#ifndef WIN32 +#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) +#endif /* WIN32 */ +#endif /* HAVE_MREMAP */ + + +/** + * Define CALL_MORECORE + */ +#if HAVE_MORECORE + #ifdef MORECORE + #define CALL_MORECORE(S) MORECORE(S) + #else /* MORECORE */ + #define CALL_MORECORE(S) MORECORE_DEFAULT(S) + #endif /* MORECORE */ +#else /* HAVE_MORECORE */ + #define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/** + * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP + */ +#if HAVE_MMAP + #define IS_MMAPPED_BIT (SIZE_T_ONE) + #define USE_MMAP_BIT (SIZE_T_ONE) + + #ifdef MMAP + #define CALL_MMAP(s) MMAP(s) + #else /* MMAP */ + #define CALL_MMAP(s) MMAP_DEFAULT(s) + #endif /* MMAP */ + #ifdef MUNMAP + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) + #else /* MUNMAP */ + #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) + #endif /* MUNMAP */ + #ifdef DIRECT_MMAP + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #else /* DIRECT_MMAP */ + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) + #endif /* DIRECT_MMAP */ +#else /* HAVE_MMAP */ + #define IS_MMAPPED_BIT (SIZE_T_ZERO) + #define USE_MMAP_BIT (SIZE_T_ZERO) + + #define MMAP(s) MFAIL + #define MUNMAP(a, s) (-1) + #define DIRECT_MMAP(s) MFAIL + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #define CALL_MMAP(s) MMAP(s) + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) +#endif /* HAVE_MMAP */ + +/** + * Define CALL_MREMAP + */ +#if HAVE_MMAP && HAVE_MREMAP + #ifdef MREMAP + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) + #else /* MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) + #endif /* MREMAP */ +#else /* HAVE_MMAP && HAVE_MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +/* mstate bit set if continguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +/* --------------------------- Lock preliminaries ------------------------ */ + +/* + When locks are defined, there is one global lock, plus + one per-mspace lock. + + The global lock_ensures that mparams.magic and other unique + mparams values are initialized only once. It also protects + sequences of calls to MORECORE. In many cases sys_alloc requires + two calls, that should not be interleaved with calls by other + threads. This does not protect against direct calls to MORECORE + by other threads not using this lock, so there is still code to + cope the best we can on interference. + + Per-mspace locks surround calls to malloc, free, etc. To enable use + in layered extensions, per-mspace locks are reentrant. + + Because lock-protected regions generally have bounded times, it is + OK to use the supplied simple spinlocks in the custom versions for + x86. + + If USE_LOCKS is > 1, the definitions of lock routines here are + bypassed, in which case you will need to define at least + INITIAL_LOCK, ACQUIRE_LOCK, RELEASE_LOCK and possibly TRY_LOCK + (which is not used in this malloc, but commonly needed in + extensions.) +*/ + +#if USE_LOCKS == 1 + +#if USE_SPIN_LOCKS +#ifndef WIN32 + +/* Custom pthread-style spin locks on x86 and x64 for gcc */ +struct pthread_mlock_t { + volatile unsigned int l; + volatile unsigned int c; + volatile pthread_t threadid; +}; +#define MLOCK_T struct pthread_mlock_t +#define CURRENT_THREAD pthread_self() +#define INITIAL_LOCK(sl) (memset(sl, 0, sizeof(MLOCK_T)), 0) +#define ACQUIRE_LOCK(sl) pthread_acquire_lock(sl) +#define RELEASE_LOCK(sl) pthread_release_lock(sl) +#define TRY_LOCK(sl) pthread_try_lock(sl) +#define SPINS_PER_YIELD 63 + +static MLOCK_T malloc_global_mutex = { 0, 0, 0}; + +static FORCEINLINE int pthread_acquire_lock (MLOCK_T *sl) { + int spins = 0; + volatile unsigned int* lp = &sl->l; + for (;;) { + if (*lp != 0) { + if (sl->threadid == CURRENT_THREAD) { + ++sl->c; + return 0; + } + } + else { + /* place args to cmpxchgl in locals to evade oddities in some gccs */ + int cmp = 0; + int val = 1; + int ret; + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(lp)), "0"(cmp) + : "memory", "cc"); + if (!ret) { + assert(!sl->threadid); + sl->c = 1; + sl->threadid = CURRENT_THREAD; + return 0; + } + if ((++spins & SPINS_PER_YIELD) == 0) { +#if defined (__SVR4) && defined (__sun) /* solaris */ + thr_yield(); +#else +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) + sched_yield(); +#else /* no-op yield on unknown systems */ + ; +#endif /* __linux__ || __FreeBSD__ || __APPLE__ */ +#endif /* solaris */ + } + } + } +} + +static FORCEINLINE void pthread_release_lock (MLOCK_T *sl) { + assert(sl->l != 0); + assert(sl->threadid == CURRENT_THREAD); + if (--sl->c == 0) { + sl->threadid = 0; + volatile unsigned int* lp = &sl->l; + int prev = 0; + int ret; + __asm__ __volatile__ ("lock; xchgl %0, %1" + : "=r" (ret) + : "m" (*(lp)), "0"(prev) + : "memory"); + } +} + +static FORCEINLINE int pthread_try_lock (MLOCK_T *sl) { + volatile unsigned int* lp = &sl->l; + if (*lp != 0) { + if (sl->threadid == CURRENT_THREAD) { + ++sl->c; + return 1; + } + } + else { + int cmp = 0; + int val = 1; + int ret; + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(lp)), "0"(cmp) + : "memory", "cc"); + if (!ret) { + assert(!sl->threadid); + sl->c = 1; + sl->threadid = CURRENT_THREAD; + return 1; + } + } + return 0; +} + + +#else /* WIN32 */ +/* Custom win32-style spin locks on x86 and x64 for MSC */ +struct win32_mlock_t +{ + volatile long l; + volatile unsigned int c; + volatile long threadid; +}; + +#define MLOCK_T struct win32_mlock_t +#define CURRENT_THREAD win32_getcurrentthreadid() +#define INITIAL_LOCK(sl) (memset(sl, 0, sizeof(MLOCK_T)), 0) +#define ACQUIRE_LOCK(sl) win32_acquire_lock(sl) +#define RELEASE_LOCK(sl) win32_release_lock(sl) +#define TRY_LOCK(sl) win32_try_lock(sl) +#define SPINS_PER_YIELD 63 + +static MLOCK_T malloc_global_mutex = { 0, 0, 0}; + +static FORCEINLINE long win32_getcurrentthreadid() { +#ifdef _MSC_VER +#if defined(_M_IX86) + long *threadstruct=(long *)__readfsdword(0x18); + long threadid=threadstruct[0x24/sizeof(long)]; + return threadid; +#elif defined(_M_X64) + /* todo */ + return GetCurrentThreadId(); +#else + return GetCurrentThreadId(); +#endif +#else + return GetCurrentThreadId(); +#endif +} + +static FORCEINLINE int win32_acquire_lock (MLOCK_T *sl) { + int spins = 0; + for (;;) { + if (sl->l != 0) { + if (sl->threadid == CURRENT_THREAD) { + ++sl->c; + return 0; + } + } + else { + if (!interlockedexchange(&sl->l, 1)) { + assert(!sl->threadid); + sl->c=CURRENT_THREAD; + sl->threadid = CURRENT_THREAD; + sl->c = 1; + return 0; + } + } + if ((++spins & SPINS_PER_YIELD) == 0) + SleepEx(0, FALSE); + } +} + +static FORCEINLINE void win32_release_lock (MLOCK_T *sl) { + assert(sl->threadid == CURRENT_THREAD); + assert(sl->l != 0); + if (--sl->c == 0) { + sl->threadid = 0; + interlockedexchange (&sl->l, 0); + } +} + +static FORCEINLINE int win32_try_lock (MLOCK_T *sl) { + if(sl->l != 0) { + if (sl->threadid == CURRENT_THREAD) { + ++sl->c; + return 1; + } + } + else { + if (!interlockedexchange(&sl->l, 1)){ + assert(!sl->threadid); + sl->threadid = CURRENT_THREAD; + sl->c = 1; + return 1; + } + } + return 0; +} + +#endif /* WIN32 */ +#else /* USE_SPIN_LOCKS */ + +#ifndef WIN32 +/* pthreads-based locks */ + +#define MLOCK_T pthread_mutex_t +#define CURRENT_THREAD pthread_self() +#define INITIAL_LOCK(sl) pthread_init_lock(sl) +#define ACQUIRE_LOCK(sl) pthread_mutex_lock(sl) +#define RELEASE_LOCK(sl) pthread_mutex_unlock(sl) +#define TRY_LOCK(sl) (!pthread_mutex_trylock(sl)) + +static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Cope with old-style linux recursive lock initialization by adding */ +/* skipped internal declaration from pthread.h */ +#ifdef linux +#ifndef PTHREAD_MUTEX_RECURSIVE +extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr, + int __kind)); +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y) +#endif +#endif + +static int pthread_init_lock (MLOCK_T *sl) { + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr)) return 1; + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1; + if (pthread_mutex_init(sl, &attr)) return 1; + if (pthread_mutexattr_destroy(&attr)) return 1; + return 0; +} + +#else /* WIN32 */ +/* Win32 critical sections */ +#define MLOCK_T CRITICAL_SECTION +#define CURRENT_THREAD GetCurrentThreadId() +#define INITIAL_LOCK(s) (!InitializeCriticalSectionAndSpinCount((s), 0x80000000|4000)) +#define ACQUIRE_LOCK(s) (EnterCriticalSection(s), 0) +#define RELEASE_LOCK(s) LeaveCriticalSection(s) +#define TRY_LOCK(s) TryEnterCriticalSection(s) +#define NEED_GLOBAL_LOCK_INIT + +static MLOCK_T malloc_global_mutex; +static volatile long malloc_global_mutex_status; + +/* Use spin loop to initialize global lock */ +static void init_malloc_global_mutex() { + for (;;) { + long stat = malloc_global_mutex_status; + if (stat > 0) + return; + /* transition to < 0 while initializing, then to > 0) */ + if (stat == 0 && + interlockedcompareexchange(&malloc_global_mutex_status, -1, 0) == 0) { + InitializeCriticalSection(&malloc_global_mutex); + interlockedexchange(&malloc_global_mutex_status,1); + return; + } + SleepEx(0, FALSE); + } +} + +#endif /* WIN32 */ +#endif /* USE_SPIN_LOCKS */ +#endif /* USE_LOCKS == 1 */ + +/* ----------------------- User-defined locks ------------------------ */ + +#if USE_LOCKS > 1 +/* Define your own lock implementation here */ +/* #define INITIAL_LOCK(sl) ... */ +/* #define ACQUIRE_LOCK(sl) ... */ +/* #define RELEASE_LOCK(sl) ... */ +/* #define TRY_LOCK(sl) ... */ +/* static MLOCK_T malloc_global_mutex = ... */ +#endif /* USE_LOCKS > 1 */ + +/* ----------------------- Lock-based state ------------------------ */ + +#if USE_LOCKS +#define USE_LOCK_BIT (2U) +#else /* USE_LOCKS */ +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) +#endif /* USE_LOCKS */ + +#if USE_LOCKS +#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); +#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); +#else /* USE_LOCKS */ +#define ACQUIRE_MALLOC_GLOBAL_LOCK() +#define RELEASE_MALLOC_GLOBAL_LOCK() +#endif /* USE_LOCKS */ + + +/* ----------------------- Chunk representations ------------------------ */ + +/* + (The following includes lightly edited explanations by Colin Plumb.) + + The malloc_chunk declaration below is misleading (but accurate and + necessary). It declares a "view" into memory allowing access to + necessary fields at known offsets from a given base. + + Chunks of memory are maintained using a `boundary tag' method as + originally described by Knuth. (See the paper by Paul Wilson + ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such + techniques.) Sizes of free chunks are stored both in the front of + each chunk and at the end. This makes consolidating fragmented + chunks into bigger chunks fast. The head fields also hold bits + representing whether chunks are free or in use. + + Here are some pictures to make it clearer. They are "exploded" to + show that the state of a chunk can be thought of as extending from + the high 31 bits of the head field of its header through the + prev_foot and PINUSE_BIT bit of the following chunk header. + + A chunk that's in use looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk (if P = 0) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 1| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +- -+ + | | + +- -+ + | : + +- size - sizeof(size_t) available payload bytes -+ + : | + chunk-> +- -+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| + | Size of next chunk (may or may not be in use) | +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + And if it's free, it looks like this: + + chunk-> +- -+ + | User payload (must be in use, or we would have merged!) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 0| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prev pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- size - sizeof(struct chunk) unused bytes -+ + : | + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| + | Size of next chunk (must be in use, or we would have merged)| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- User payload -+ + : | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0| + +-+ + Note that since we always merge adjacent free chunks, the chunks + adjacent to a free chunk must be in use. + + Given a pointer to a chunk (which can be derived trivially from the + payload pointer) we can, in O(1) time, find out whether the adjacent + chunks are free, and if so, unlink them from the lists that they + are on and merge them with the current chunk. + + Chunks always begin on even word boundaries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + The P (PINUSE_BIT) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, preventing + access to non-existent (or non-owned) memory. If pinuse is set for + any given chunk, then you CANNOT determine the size of the + previous chunk, and might even get a memory addressing fault when + trying to do so. + + The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of + the chunk size redundantly records whether the current chunk is + inuse. This redundancy enables usage checks within free and realloc, + and reduces indirection when freeing and consolidating chunks. + + Each freshly allocated chunk must have both cinuse and pinuse set. + That is, each allocated chunk borders either a previously allocated + and still in-use chunk, or the base of its memory arena. This is + ensured by making all allocations from the the `lowest' part of any + found chunk. Further, no free chunk physically borders another one, + so each free chunk is known to be preceded and followed by either + inuse chunks or the ends of memory. + + Note that the `foot' of the current chunk is actually represented + as the prev_foot of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The exceptions to all this are + + 1. The special chunk `top' is the top-most available chunk (i.e., + the one bordering the end of available memory). It is treated + specially. Top is never included in any bin, is used only if + no other chunk is available, and is released back to the + system if it is very large (see M_TRIM_THRESHOLD). In effect, + the top chunk is treated as larger (and thus less well + fitting) than any other available chunk. The top chunk + doesn't update its trailing size field since there is no next + contiguous chunk that would have to index off it. However, + space is still allocated for it (TOP_FOOT_SIZE) to enable + separation or merging when space is extended. + + 3. Chunks allocated via mmap, which have the lowest-order bit + (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set + PINUSE_BIT in their head fields. Because they are allocated + one-by-one, each must carry its own prev_foot field, which is + also used to hold the offset this chunk has within its mmapped + region, which is needed to preserve alignment. Each mmapped + chunk is trailed by the first two fields of a fake next-chunk + for sake of usage checks. + +*/ + +struct malloc_chunk { + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + +/* ------------------- Chunks sizes and alignments ----------------------- */ + +#define MCHUNK_SIZE (sizeof(mchunk)) + +#if FOOTERS +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define pad_request(req) \ + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define request2size(req) \ + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + + +/* ------------------ Operations on head and foot fields ----------------- */ + +/* + The head field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use. If the chunk was obtained with mmap, the prev_foot field has + IS_MMAPPED_BIT set, otherwise holding the offset of the base of the + mmapped region to the base of the chunk. + + FLAG4_BIT is not used by this malloc, but might be useful in extensions. +*/ + +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define FLAG4_BIT (SIZE_T_FOUR) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) +#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from head words */ +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define chunksize(p) ((p)->head & ~(FLAG_BITS)) + +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) + +/* extract next chunk's pinuse bit */ +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) + +/* Get/set size at footer */ +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) + +/* Set size, pinuse bit, and foot */ +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) + +/* Set size, pinuse bit, foot, and clear next pinuse */ +#define set_free_with_pinuse(p, s, n)\ + (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) + +#define is_mmapped(p)\ + (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT)) + +/* Get the internal overhead associated with chunk p */ +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ + +/* + When chunks are not in use, they are treated as nodes of either + lists or trees. + + "Small" chunks are stored in circular doubly-linked lists, and look + like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Larger chunks are kept in a form of bitwise digital trees (aka + tries) keyed on chunksizes. Because malloc_tree_chunks are only for + free chunks greater than 256 bytes, their size doesn't impose any + constraints on user chunk sizes. Each node looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to left child (child[0]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to right child (child[1]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to parent | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | bin index of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Each tree holding treenodes is a tree of unique chunk sizes. Chunks + of the same size are arranged in a circularly-linked list, with only + the oldest chunk (the next to be used, in our FIFO ordering) + actually in the tree. (Tree members are distinguished by a non-null + parent pointer.) If a chunk with the same size an an existing node + is inserted, it is linked off the existing node using pointers that + work in the same way as fd/bk pointers of small chunks. + + Each tree contains a power of 2 sized range of chunk sizes (the + smallest is 0x100 <= x < 0x180), which is is divided in half at each + tree level, with the chunks in the smaller half of the range (0x100 + <= x < 0x140 for the top nose) in the left subtree and the larger + half (0x140 <= x < 0x180) in the right subtree. This is, of course, + done by inspecting individual bits. + + Using these rules, each node's left subtree contains all smaller + sizes than its right subtree. However, the node at the root of each + subtree has no particular ordering relationship to either. (The + dividing line between the subtree sizes is based on trie relation.) + If we remove the last chunk of a given size from the interior of the + tree, we need to replace it with a leaf node. The tree ordering + rules permit a node to be replaced by any leaf below it. + + The smallest chunk in a tree (a common operation in a best-fit + allocator) can be found by walking a path to the leftmost leaf in + the tree. Unlike a usual binary tree, where we follow left child + pointers until we reach a null, here we follow the right child + pointer any time the left one is null, until we reach a leaf with + both child pointers null. The smallest chunk in the tree will be + somewhere along that path. + + The worst case number of steps to add, find, or remove a node is + bounded by the number of bits differentiating chunks within + bins. Under current bin calculations, this ranges from 6 up to 21 + (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case + is of course much better. +*/ + +struct malloc_tree_chunk { + /* The first four fields must be compatible with malloc_chunk */ + size_t prev_foot; + size_t head; + struct malloc_tree_chunk* fd; + struct malloc_tree_chunk* bk; + + struct malloc_tree_chunk* child[2]; + struct malloc_tree_chunk* parent; + bindex_t index; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) + +/* ----------------------------- Segments -------------------------------- */ + +/* + Each malloc space may include non-contiguous segments, held in a + list headed by an embedded malloc_segment record representing the + top-most space. Segments also include flags holding properties of + the space. Large chunks that are directly allocated by mmap are not + included in this list. They are instead independently created and + destroyed without otherwise keeping track of them. + + Segment management mainly comes into play for spaces allocated by + MMAP. Any call to MMAP might or might not return memory that is + adjacent to an existing segment. MORECORE normally contiguously + extends the current space, so this space is almost always adjacent, + which is simpler and faster to deal with. (This is why MORECORE is + used preferentially to MMAP when both are available -- see + sys_alloc.) When allocating using MMAP, we don't use any of the + hinting mechanisms (inconsistently) supported in various + implementations of unix mmap, or distinguish reserving from + committing memory. Instead, we just ask for space, and exploit + contiguity when we get it. It is probably possible to do + better than this on some systems, but no general scheme seems + to be significantly better. + + Management entails a simpler variant of the consolidation scheme + used for chunks to reduce fragmentation -- new adjacent memory is + normally prepended or appended to an existing segment. However, + there are limitations compared to chunk consolidation that mostly + reflect the fact that segment processing is relatively infrequent + (occurring only when getting memory from system) and that we + don't expect to have huge numbers of segments: + + * Segments are not indexed, so traversal requires linear scans. (It + would be possible to index these, but is not worth the extra + overhead and complexity for most programs on most platforms.) + * New segments are only appended to old ones when holding top-most + memory; if they cannot be prepended to others, they are held in + different segments. + + Except for the top-most segment of an mstate, each segment record + is kept at the tail of its segment. Segments are added by pushing + segment records onto the list headed by &mstate.seg for the + containing mstate. + + Segment flags control allocation/merge/deallocation policies: + * If EXTERN_BIT set, then we did not allocate this segment, + and so should not try to deallocate or merge with others. + (This currently holds only for the initial segment passed + into create_mspace_with_base.) + * If IS_MMAPPED_BIT set, the segment may be merged with + other surrounding mmapped segments and trimmed/de-allocated + using munmap. + * If neither bit is set, then the segment was obtained using + MORECORE so can be merged with surrounding MORECORE'd segments + and deallocated/trimmed using MORECORE with negative arguments. +*/ + +struct malloc_segment { + char* base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment* next; /* ptr to next segment */ + flag_t sflags; /* mmap and extern flag */ +}; + +#define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT) +#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment* msegmentptr; + +/* ---------------------------- malloc_state ----------------------------- */ + +/* + A malloc_state holds all of the bookkeeping for a space. + The main fields are: + + Top + The topmost chunk of the currently active segment. Its size is + cached in topsize. The actual size of topmost space is + topsize+TOP_FOOT_SIZE, which includes space reserved for adding + fenceposts and segment records if necessary when getting more + space from the system. The size at which to autotrim top is + cached from mparams in trim_check, except that it is disabled if + an autotrim fails. + + Designated victim (dv) + This is the preferred chunk for servicing small requests that + don't have exact fits. It is normally the chunk split off most + recently to service another small request. Its size is cached in + dvsize. The link fields of this chunk are not maintained since it + is not kept in a bin. + + SmallBins + An array of bin headers for free chunks. These bins hold chunks + with sizes less than MIN_LARGE_SIZE bytes. Each bin contains + chunks of all the same size, spaced 8 bytes apart. To simplify + use in double-linked lists, each bin header acts as a malloc_chunk + pointing to the real first node, if it exists (else pointing to + itself). This avoids special-casing for headers. But to avoid + waste, we allocate only the fd/bk pointers of bins, and then use + repositioning tricks to treat these as the fields of a chunk. + + TreeBins + Treebins are pointers to the roots of trees holding a range of + sizes. There are 2 equally spaced treebins for each power of two + from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything + larger. + + Bin maps + There is one bit map for small bins ("smallmap") and one for + treebins ("treemap). Each bin sets its bit when non-empty, and + clears the bit when empty. Bit operations are then used to avoid + bin-by-bin searching -- nearly all "search" is done without ever + looking at bins that won't be selected. The bit maps + conservatively use 32 bits per map word, even if on 64bit system. + For a good description of some of the bit-based techniques used + here, see Henry S. Warren Jr's book "Hacker's Delight" (and + supplement at http://hackersdelight.org/). Many of these are + intended to reduce the branchiness of paths through malloc etc, as + well as to reduce the number of memory locations read or written. + + Segments + A list of segments headed by an embedded malloc_segment record + representing the initial space. + + Address check support + The least_addr field is the least address ever obtained from + MORECORE or MMAP. Attempted frees and reallocs of any address less + than this are trapped (unless INSECURE is defined). + + Magic tag + A cross-check field that should always hold same value as mparams.magic. + + Flags + Bits recording whether to use MMAP, locks, or contiguous MORECORE + + Statistics + Each space keeps track of current and maximum system memory + obtained via MORECORE or MMAP. + + Trim support + Fields holding the amount of unused topmost memory that should trigger + timming, and a counter to force periodic scanning to release unused + non-topmost segments. + + Locking + If USE_LOCKS is defined, the "mutex" lock is acquired and released + around every public call using this mspace. + + Extension support + A void* pointer and a size_t field that can be used to help implement + extensions to this malloc. +*/ + +/* Bin types, widths and sizes */ +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +struct malloc_state { + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char* least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t release_checks; + size_t magic; + mchunkptr smallbins[(NSMALLBINS+1)*2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + flag_t mflags; +#if USE_LOCKS + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; + void* extp; /* Unused but available for extensions */ + size_t exts; +}; + +typedef struct malloc_state* mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. Note that the non-zeroness of "magic" + also serves as an initialization flag. +*/ + +struct malloc_params { + volatile size_t magic; + size_t page_size; + size_t granularity; + size_t mmap_threshold; + size_t trim_threshold; + flag_t default_mflags; +}; + +static struct malloc_params mparams; + +/* Ensure mparams initialized */ +#define ensure_initialization() (mparams.magic != 0 || init_mparams()) + +#if !ONLY_MSPACES + +/* The global malloc_state used for all non-"mspace" calls */ +static struct malloc_state _gm_; +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) + +#endif /* !ONLY_MSPACES */ + +#define is_initialized(M) ((M)->top != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on mflags */ + +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) + +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) + +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) + +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define page_align(S)\ + (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) + +/* granularity-align a size */ +#define granularity_align(S)\ + (((S) + (mparams.granularity - SIZE_T_ONE))\ + & ~(mparams.granularity - SIZE_T_ONE)) + + +/* For mmap, use granularity alignment on windows, else page-align */ +#ifdef WIN32 +#define mmap_align(S) granularity_align(S) +#else +#define mmap_align(S) page_align(S) +#endif + +/* For sys_alloc, enough padding to ensure can malloc request on success */ +#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) + +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) + +/* Return segment holding given address */ +static msegmentptr segment_holding(mstate m, char* addr) { + msegmentptr sp = &m->seg; + for (;;) { + if (addr >= sp->base && addr < sp->base + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; + } +} + +/* Return true if segment contains a segment link */ +static int has_segment_link(mstate m, msegmentptr ss) { + msegmentptr sp = &m->seg; + for (;;) { + if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) + return 1; + if ((sp = sp->next) == 0) + return 0; + } +} + +#ifndef MORECORE_CANNOT_TRIM +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + + +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS + +#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ + +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ + +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ + +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + +/* A count of the number of corruption errors causing resets */ +int malloc_corruption_error_count; + +/* default corruption action */ +static void reset_on_error(mstate m); + +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) + +#else /* PROCEED_ON_ERROR */ + +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ + +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ + +/* -------------------------- Debugging setup ---------------------------- */ + +#if ! DEBUG + +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) + +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) + +static void do_check_any_chunk(mstate m, mchunkptr p); +static void do_check_top_chunk(mstate m, mchunkptr p); +static void do_check_mmapped_chunk(mstate m, mchunkptr p); +static void do_check_inuse_chunk(mstate m, mchunkptr p); +static void do_check_free_chunk(mstate m, mchunkptr p); +static void do_check_malloced_chunk(mstate m, void* mem, size_t s); +static void do_check_tree(mstate m, tchunkptr t); +static void do_check_treebin(mstate m, bindex_t i); +static void do_check_smallbin(mstate m, bindex_t i); +static void do_check_malloc_state(mstate m); +static int bin_find(mstate m, mchunkptr x); +static size_t traverse_and_check(mstate m); +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) ((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) + +/* assign tree index for size S to variable I. Use x86 asm if possible */ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_tree_index(S, I)\ +{\ + unsigned int X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + __asm__("bsrl\t%1, %0\n\t" : "=r" (K) : "rm" (X));\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = _bit_scan_reverse (X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + _BitScanReverse((DWORD *) &K, X);\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ + +/* Bit representing maximum resolved size in a treebin at i */ +#define bit_for_tree_index(i) \ + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define leftshift_for_tree_index(i) \ + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ + +/* bit corresponding to given index */ +#define idx2bit(i) ((binmap_t)(1) << (i)) + +/* Mark/Clear bits with given index */ +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) + +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) + +/* isolate the least set bit of a bitmap */ +#define least_bit(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define left_bits(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define same_or_left_bits(x) ((x) | -(x)) + +/* index corresponding to given bit. Use x86 asm if possible */ + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + __asm__("bsfl\t%1, %0\n\t" : "=r" (J) : "rm" (X));\ + I = (bindex_t)J;\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = _bit_scan_forward (X); \ + I = (bindex_t)J;\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + _BitScanForward((DWORD *) &J, X);\ + I = (bindex_t)J;\ +} + +#elif USE_BUILTIN_FFS +#define compute_bit2idx(X, I) I = ffs(X)-1 + +#else +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* GNUC */ + + +/* ----------------------- Runtime Check Support ------------------------- */ + +/* + For security, the main invariant is that malloc/free/etc never + writes to a static address other than malloc_state, unless static + malloc_state itself has been corrupted, which cannot occur via + malloc (because of these checks). In essence this means that we + believe all pointers, sizes, maps etc held in malloc_state, but + check all of those linked or offsetted from other embedded data + structures. These checks are interspersed with main code in a way + that tends to minimize their run-time cost. + + When FOOTERS is defined, in addition to range checking, we also + verify footer fields of inuse chunks, which can be used guarantee + that the mstate controlling malloc/free is intact. This is a + streamlined version of the approach described by William Robertson + et al in "Run-time Detection of Heap-based Overflows" LISA'03 + http://www.usenix.org/events/lisa03/tech/robertson.html The footer + of an inuse chunk holds the xor of its mstate and a random seed, + that is checked upon calls to free() and realloc(). This is + (probablistically) unguessable from outside the program, but can be + computed by any code successfully malloc'ing any chunk, so does not + itself provide protection against code that has already broken + security through some other means. Unlike Robertson et al, we + always dynamically check addresses of all offset chunks (previous, + next, etc). This turns out to be cheaper than relying on hashes. +*/ + +#if !INSECURE +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has its cinuse bit on */ +#define ok_cinuse(p) cinuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_cinuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ + +/* macros to set up inuse chunks with or without footers */ + +#if !FOOTERS + +#define mark_inuse_foot(M,p,s) + +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) + +#else /* FOOTERS */ + +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) + +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) + +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) + +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) + +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) + +#endif /* !FOOTERS */ + +/* ---------------------------- setting mparams -------------------------- */ + +/* Initialize mparams */ +static int init_mparams(void) { +#ifdef NEED_GLOBAL_LOCK_INIT + if (malloc_global_mutex_status <= 0) + init_malloc_global_mutex(); +#endif + + ACQUIRE_MALLOC_GLOBAL_LOCK(); + if (mparams.magic == 0) { + size_t magic; + size_t psize; + size_t gsize; + +#ifndef WIN32 + psize = malloc_getpagesize; + gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize); +#else /* WIN32 */ + { + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + psize = system_info.dwPageSize; + gsize = ((DEFAULT_GRANULARITY != 0)? + DEFAULT_GRANULARITY : system_info.dwAllocationGranularity); + } +#endif /* WIN32 */ + + /* Sanity-check configuration: + size_t must be unsigned and as wide as pointer type. + ints must be at least 4 bytes. + alignment must be at least 8. + Alignment, min chunk size, and page size must all be powers of 2. + */ + if ((sizeof(size_t) != sizeof(char*)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || + ((gsize & (gsize-SIZE_T_ONE)) != 0) || + ((psize & (psize-SIZE_T_ONE)) != 0)) + ABORT; + + mparams.granularity = gsize; + mparams.page_size = psize; + mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; +#if MORECORE_CONTIGUOUS + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ + +#if !ONLY_MSPACES + /* Set up lock for main malloc area */ + gm->mflags = mparams.default_mflags; + INITIAL_LOCK(&gm->mutex); +#endif + +#if (FOOTERS && !INSECURE) + { +#if USE_DEV_RANDOM + int fd; + unsigned char buf[sizeof(size_t)]; + /* Try to use /dev/urandom, else fall back on using time */ + if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && + read(fd, buf, sizeof(buf)) == sizeof(buf)) { + magic = *((size_t *) buf); + close(fd); + } + else +#endif /* USE_DEV_RANDOM */ +#ifdef WIN32 + magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); +#else + magic = (size_t)(time(0) ^ (size_t)0x55555555U); +#endif + magic |= (size_t)8U; /* ensure nonzero */ + magic &= ~(size_t)7U; /* improve chances of fault for bad values */ + } +#else /* (FOOTERS && !INSECURE) */ + magic = (size_t)0x58585858U; +#endif /* (FOOTERS && !INSECURE) */ + + mparams.magic = magic; + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + return 1; +} + +/* support for mallopt */ +static int change_mparam(int param_number, int value) { + size_t val = (value == -1)? MAX_SIZE_T : (size_t)value; + ensure_initialization(); + switch(param_number) { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val-1)) == 0)) { + mparams.granularity = val; + return 1; + } + else + return 0; + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + default: + return 0; + } +} + +#if DEBUG +/* ------------------------- Debugging Support --------------------------- */ + +/* Check properties of any chunk, whether free, inuse, mmapped etc */ +static void do_check_any_chunk(mstate m, mchunkptr p) { + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); +} + +/* Check properties of top chunk */ +static void do_check_top_chunk(mstate m, mchunkptr p) { + msegmentptr sp = segment_holding(m, (char*)p); + size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */ + assert(sp != 0); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(sz == m->topsize); + assert(sz > 0); + assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); + assert(pinuse(p)); + assert(!pinuse(chunk_plus_offset(p, sz))); +} + +/* Check properties of (inuse) mmapped chunks */ +static void do_check_mmapped_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD); + assert(is_mmapped(p)); + assert(use_mmap(m)); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(!is_small(sz)); + assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); + assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); + assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); +} + +/* Check properties of inuse chunks */ +static void do_check_inuse_chunk(mstate m, mchunkptr p) { + do_check_any_chunk(m, p); + assert(cinuse(p)); + assert(next_pinuse(p)); + /* If not pinuse and not mmapped, previous chunk has OK offset */ + assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); + if (is_mmapped(p)) + do_check_mmapped_chunk(m, p); +} + +/* Check properties of free chunks */ +static void do_check_free_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + mchunkptr next = chunk_plus_offset(p, sz); + do_check_any_chunk(m, p); + assert(!cinuse(p)); + assert(!next_pinuse(p)); + assert (!is_mmapped(p)); + if (p != m->dv && p != m->top) { + if (sz >= MIN_CHUNK_SIZE) { + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(is_aligned(chunk2mem(p))); + assert(next->prev_foot == sz); + assert(pinuse(p)); + assert (next == m->top || cinuse(next)); + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_T_SIZE */ + assert(sz == SIZE_T_SIZE); + } +} + +/* Check properties of malloced chunks at the point they are malloced */ +static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); + do_check_inuse_chunk(m, p); + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(sz >= MIN_CHUNK_SIZE); + assert(sz >= s); + /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ + assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); + } +} + +/* Check a tree and its subtrees. */ +static void do_check_tree(mstate m, tchunkptr t) { + tchunkptr head = 0; + tchunkptr u = t; + bindex_t tindex = t->index; + size_t tsize = chunksize(t); + bindex_t idx; + compute_tree_index(tsize, idx); + assert(tindex == idx); + assert(tsize >= MIN_LARGE_SIZE); + assert(tsize >= minsize_for_tree_index(idx)); + assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); + + do { /* traverse through chain of same-sized nodes */ + do_check_any_chunk(m, ((mchunkptr)u)); + assert(u->index == tindex); + assert(chunksize(u) == tsize); + assert(!cinuse(u)); + assert(!next_pinuse(u)); + assert(u->fd->bk == u); + assert(u->bk->fd == u); + if (u->parent == 0) { + assert(u->child[0] == 0); + assert(u->child[1] == 0); + } + else { + assert(head == 0); /* only one node on chain has parent */ + head = u; + assert(u->parent != u); + assert (u->parent->child[0] == u || + u->parent->child[1] == u || + *((tbinptr*)(u->parent)) == u); + if (u->child[0] != 0) { + assert(u->child[0]->parent == u); + assert(u->child[0] != u); + do_check_tree(m, u->child[0]); + } + if (u->child[1] != 0) { + assert(u->child[1]->parent == u); + assert(u->child[1] != u); + do_check_tree(m, u->child[1]); + } + if (u->child[0] != 0 && u->child[1] != 0) { + assert(chunksize(u->child[0]) < chunksize(u->child[1])); + } + } + u = u->fd; + } while (u != t); + assert(head != 0); +} + +/* Check all the chunks in a treebin. */ +static void do_check_treebin(mstate m, bindex_t i) { + tbinptr* tb = treebin_at(m, i); + tchunkptr t = *tb; + int empty = (m->treemap & (1U << i)) == 0; + if (t == 0) + assert(empty); + if (!empty) + do_check_tree(m, t); +} + +/* Check all the chunks in a smallbin. */ +static void do_check_smallbin(mstate m, bindex_t i) { + sbinptr b = smallbin_at(m, i); + mchunkptr p = b->bk; + unsigned int empty = (m->smallmap & (1U << i)) == 0; + if (p == b) + assert(empty); + if (!empty) { + for (; p != b; p = p->bk) { + size_t size = chunksize(p); + mchunkptr q; + /* each chunk claims to be free */ + do_check_free_chunk(m, p); + /* chunk belongs in bin */ + assert(small_index(size) == i); + assert(p->bk == b || chunksize(p->bk) == chunksize(p)); + /* chunk is followed by an inuse chunk */ + q = next_chunk(p); + if (q->head != FENCEPOST_HEAD) + do_check_inuse_chunk(m, q); + } + } +} + +/* Find x in a bin. Used in other check functions. */ +static int bin_find(mstate m, mchunkptr x) { + size_t size = chunksize(x); + if (is_small(size)) { + bindex_t sidx = small_index(size); + sbinptr b = smallbin_at(m, sidx); + if (smallmap_is_marked(m, sidx)) { + mchunkptr p = b; + do { + if (p == x) + return 1; + } while ((p = p->fd) != b); + } + } + else { + bindex_t tidx; + compute_tree_index(size, tidx); + if (treemap_is_marked(m, tidx)) { + tchunkptr t = *treebin_at(m, tidx); + size_t sizebits = size << leftshift_for_tree_index(tidx); + while (t != 0 && chunksize(t) != size) { + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + sizebits <<= 1; + } + if (t != 0) { + tchunkptr u = t; + do { + if (u == (tchunkptr)x) + return 1; + } while ((u = u->fd) != t); + } + } + } + return 0; +} + +/* Traverse each chunk and check it; return total */ +static size_t traverse_and_check(mstate m) { + size_t sum = 0; + if (is_initialized(m)) { + msegmentptr s = &m->seg; + sum += m->topsize + TOP_FOOT_SIZE; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + mchunkptr lastq = 0; + assert(pinuse(q)); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + sum += chunksize(q); + if (cinuse(q)) { + assert(!bin_find(m, q)); + do_check_inuse_chunk(m, q); + } + else { + assert(q == m->dv || bin_find(m, q)); + assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */ + do_check_free_chunk(m, q); + } + lastq = q; + q = next_chunk(q); + } + s = s->next; + } + } + return sum; +} + +/* Check all properties of malloc_state. */ +static void do_check_malloc_state(mstate m) { + bindex_t i; + size_t total; + /* check bins */ + for (i = 0; i < NSMALLBINS; ++i) + do_check_smallbin(m, i); + for (i = 0; i < NTREEBINS; ++i) + do_check_treebin(m, i); + + if (m->dvsize != 0) { /* check dv chunk */ + do_check_any_chunk(m, m->dv); + assert(m->dvsize == chunksize(m->dv)); + assert(m->dvsize >= MIN_CHUNK_SIZE); + assert(bin_find(m, m->dv) == 0); + } + + if (m->top != 0) { /* check top chunk */ + do_check_top_chunk(m, m->top); + /*assert(m->topsize == chunksize(m->top)); redundant */ + assert(m->topsize > 0); + assert(bin_find(m, m->top) == 0); + } + + total = traverse_and_check(m); + assert(total <= m->footprint); + assert(m->footprint <= m->max_footprint); +} +#endif /* DEBUG */ + +/* ----------------------------- statistics ------------------------------ */ + +#if !NO_MALLINFO +static struct mallinfo internal_mallinfo(mstate m) { + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + ensure_initialization(); + if (!PREACTION(m)) { + check_malloc_state(m); + if (is_initialized(m)) { + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; + msegmentptr s = &m->seg; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + size_t sz = chunksize(q); + sum += sz; + if (!cinuse(q)) { + mfree += sz; + ++nfree; + } + q = next_chunk(q); + } + s = s->next; + } + + nm.arena = sum; + nm.ordblks = nfree; + nm.hblkhd = m->footprint - sum; + nm.usmblks = m->max_footprint; + nm.uordblks = m->footprint - mfree; + nm.fordblks = mfree; + nm.keepcost = m->topsize; + } + + POSTACTION(m); + } + return nm; +} +#endif /* !NO_MALLINFO */ + +static void internal_malloc_stats(mstate m) { + ensure_initialization(); + if (!PREACTION(m)) { + size_t maxfp = 0; + size_t fp = 0; + size_t used = 0; + check_malloc_state(m); + if (is_initialized(m)) { + msegmentptr s = &m->seg; + maxfp = m->max_footprint; + fp = m->footprint; + used = fp - (m->topsize + TOP_FOOT_SIZE); + + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + if (!cinuse(q)) + used -= chunksize(q); + q = next_chunk(q); + } + s = s->next; + } + } + + fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); + fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); + fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); + + POSTACTION(m); + } +} + +/* ----------------------- Operations on smallbins ----------------------- */ + +/* + Various forms of linking and unlinking are defined as macros. Even + the ones for trees, which are very long but have very short typical + paths. This is ugly but reduces reliance on inlining support of + compilers. +*/ + +/* Link a free chunk into a smallbin */ +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} + +/* Unlink a chunk from a smallbin */ +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (F == B)\ + clear_smallmap(M, I);\ + else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\ + (B == smallbin_at(M,I) || ok_address(M, B)))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Unlink the first chunk from a smallbin */ +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F)\ + clear_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, F))) {\ + B->fd = F;\ + F->bk = B;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + + + +/* Replace dv node, binning the old one */ +/* Used only when dvsize known to be small */ +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + assert(is_small(DVS));\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} + +/* + Unlink steps: + + 1. If x is a chained node, unlink it from its same-sized fd/bk links + and choose its bk node as its replacement. + 2. If x was the last node of its size, but not a leaf node, it must + be replaced with a leaf node (not merely one with an open left or + right), to make sure that lefts and rights of descendents + correspond properly to bit masks. We use the rightmost descendent + of x. We could use any other leaf, but this is easy to locate and + tends to counteract removal of leftmosts elsewhere, and so keeps + paths shorter than minimally guaranteed. This doesn't loop much + because on average a node in a tree is near the bottom. + 3. If x is the base of a chain (i.e., has parent links) relink + x's parent and children to x's replacement (or null if none). +*/ + +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F))) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} + +/* Relays to large vs small bin operations */ + +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } + + +/* Relays to internal calls to malloc/free from realloc, memalign etc */ + +#if ONLY_MSPACES +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + (m == gm)? dlmalloc(b) : mspace_malloc(m, b) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + +/* ----------------------- Direct-mmapping chunks ----------------------- */ + +/* + Directly mmapped chunks are set up with an offset to the start of + the mmapped region stored in the prev_foot field of the chunk. This + allows reconstruction of the required argument to MUNMAP when freed, + and also allows adjustment of the returned chunk to meet alignment + requirements (especially in memalign). There is also enough space + allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain + the PINUSE bit so frees can be checked. +*/ + +/* Malloc using mmap */ +static void* mmap_alloc(mstate m, size_t nb) { + size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + if (mmsize > nb) { /* Check for wrap around 0 */ + char* mm = (char*)(CALL_DIRECT_MMAP(mmsize)); + if (mm != CMFAIL) { + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; + mchunkptr p = (mchunkptr)(mm + offset); + p->prev_foot = offset | IS_MMAPPED_BIT; + (p)->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, p, psize); + chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; + + if (mm < m->least_addr) + m->least_addr = mm; + if ((m->footprint += mmsize) > m->max_footprint) + m->max_footprint = m->footprint; + assert(is_aligned(chunk2mem(p))); + check_mmapped_chunk(m, p); + return chunk2mem(p); + } + } + return 0; +} + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) { + size_t oldsize = chunksize(oldp); + if (is_small(nb)) /* Can't shrink mmap regions below small size */ + return 0; + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (mparams.granularity << 1)) + return oldp; + else { + size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, 1); + if (cp != CMFAIL) { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + m->max_footprint = m->footprint; + check_mmapped_chunk(m, newp); + return newp; + } + } + return 0; +} + +/* -------------------------- mspace management -------------------------- */ + +/* Initialize top chunk and its size */ +static void init_top(mstate m, mchunkptr p, size_t psize) { + /* Ensure alignment */ + size_t offset = align_offset(chunk2mem(p)); + p = (mchunkptr)((char*)p + offset); + psize -= offset; + + m->top = p; + m->topsize = psize; + p->head = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; + m->trim_check = mparams.trim_threshold; /* reset on each update */ +} + +/* Initialize bins for a new mstate that is otherwise zeroed out */ +static void init_bins(mstate m) { + /* Establish circular links for smallbins */ + bindex_t i; + for (i = 0; i < NSMALLBINS; ++i) { + sbinptr bin = smallbin_at(m,i); + bin->fd = bin->bk = bin; + } +} + +#if PROCEED_ON_ERROR + +/* default corruption action */ +static void reset_on_error(mstate m) { + int i; + ++malloc_corruption_error_count; + /* Reinitialize fields to forget about all memory */ + m->smallbins = m->treebins = 0; + m->dvsize = m->topsize = 0; + m->seg.base = 0; + m->seg.size = 0; + m->seg.next = 0; + m->top = m->dv = 0; + for (i = 0; i < NTREEBINS; ++i) + *treebin_at(m, i) = 0; + init_bins(m); +} +#endif /* PROCEED_ON_ERROR */ + +/* Allocate chunk and prepend remainder with chunk in successor base. */ +static void* prepend_alloc(mstate m, char* newbase, char* oldbase, + size_t nb) { + mchunkptr p = align_as_chunk(newbase); + mchunkptr oldfirst = align_as_chunk(oldbase); + size_t psize = (char*)oldfirst - (char*)p; + mchunkptr q = chunk_plus_offset(p, nb); + size_t qsize = psize - nb; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + + assert((char*)oldfirst > (char*)q); + assert(pinuse(oldfirst)); + assert(qsize >= MIN_CHUNK_SIZE); + + /* consolidate remainder with first chunk of old base */ + if (oldfirst == m->top) { + size_t tsize = m->topsize += qsize; + m->top = q; + q->head = tsize | PINUSE_BIT; + check_top_chunk(m, q); + } + else if (oldfirst == m->dv) { + size_t dsize = m->dvsize += qsize; + m->dv = q; + set_size_and_pinuse_of_free_chunk(q, dsize); + } + else { + if (!cinuse(oldfirst)) { + size_t nsize = chunksize(oldfirst); + unlink_chunk(m, oldfirst, nsize); + oldfirst = chunk_plus_offset(oldfirst, nsize); + qsize += nsize; + } + set_free_with_pinuse(q, qsize, oldfirst); + insert_chunk(m, q, qsize); + check_free_chunk(m, q); + } + + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); +} + +/* Add a segment to hold a new noncontiguous region */ +static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { + /* Determine locations and sizes of segment, fenceposts, old top */ + char* old_top = (char*)m->top; + msegmentptr oldsp = segment_holding(m, old_top); + char* old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char* asp = rawsp + offset; + char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; + mchunkptr sp = (mchunkptr)csp; + msegmentptr ss = (msegmentptr)(chunk2mem(sp)); + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; + + /* reset top to new space */ + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + + /* Set up segment record */ + assert(is_aligned(ss)); + set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); + *ss = m->seg; /* Push current record */ + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmapped; + m->seg.next = ss; + + /* Insert trailing fenceposts */ + for (;;) { + mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); + p->head = FENCEPOST_HEAD; + ++nfences; + if ((char*)(&(nextp->head)) < old_end) + p = nextp; + else + break; + } + assert(nfences >= 2); + + /* Insert the rest of old top into a bin as an ordinary free chunk */ + if (csp != old_top) { + mchunkptr q = (mchunkptr)old_top; + size_t psize = csp - old_top; + mchunkptr tn = chunk_plus_offset(q, psize); + set_free_with_pinuse(q, psize, tn); + insert_chunk(m, q, psize); + } + + check_top_chunk(m, m->top); +} + +/* -------------------------- System allocation -------------------------- */ + +/* Get memory from system using MORECORE or MMAP */ +static void* sys_alloc(mstate m, size_t nb) { + char* tbase = CMFAIL; + size_t tsize = 0; + flag_t mmap_flag = 0; + + ensure_initialization(); + + /* Directly map large chunks */ + if (use_mmap(m) && nb >= mparams.mmap_threshold) { + void* mem = mmap_alloc(m, nb); + if (mem != 0) + return mem; + } + + /* + Try getting memory in any of three ways (in most-preferred to + least-preferred order): + 1. A call to MORECORE that can normally contiguously extend memory. + (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or + or main space is mmapped or a previous contiguous call failed) + 2. A call to MMAP new space (disabled if not HAVE_MMAP). + Note that under the default settings, if MORECORE is unable to + fulfill a request, and HAVE_MMAP is true, then mmap is + used as a noncontiguous system allocator. This is a useful backup + strategy for systems with holes in address spaces -- in this case + sbrk cannot contiguously expand the heap, but mmap may be able to + find space. + 3. A call to MORECORE that cannot usually contiguously extend memory. + (disabled if not HAVE_MORECORE) + + In all cases, we need to request enough bytes from system to ensure + we can malloc nb bytes upon success, so pad with enough space for + top_foot, plus alignment-pad to make sure we don't lose bytes if + not on boundary, and round this up to a granularity unit. + */ + + if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { + char* br = CMFAIL; + msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); + size_t asize = 0; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + + if (ss == 0) { /* First time through or recovery */ + char* base = (char*)CALL_MORECORE(0); + if (base != CMFAIL) { + asize = granularity_align(nb + SYS_ALLOC_PADDING); + /* Adjust to end on a page boundary */ + if (!is_page_aligned(base)) + asize += (page_align((size_t)base) - (size_t)base); + /* Can't call MORECORE if size is negative when treated as signed */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == base) { + tbase = base; + tsize = asize; + } + } + } + else { + /* Subtract out existing available top space from MORECORE request. */ + asize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING); + /* Use mem here only if it did continuously extend old space */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) { + tbase = br; + tsize = asize; + } + } + + if (tbase == CMFAIL) { /* Cope with partial failure */ + if (br != CMFAIL) { /* Try to use/extend the space we did get */ + if (asize < HALF_MAX_SIZE_T && + asize < nb + SYS_ALLOC_PADDING) { + size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - asize); + if (esize < HALF_MAX_SIZE_T) { + char* end = (char*)CALL_MORECORE(esize); + if (end != CMFAIL) + asize += esize; + else { /* Can't use; try to release */ + (void) CALL_MORECORE(-asize); + br = CMFAIL; + } + } + } + } + if (br != CMFAIL) { /* Use the space we did get */ + tbase = br; + tsize = asize; + } + else + disable_contiguous(m); /* Don't try contiguous path in the future */ + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + } + + if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ + size_t rsize = granularity_align(nb + SYS_ALLOC_PADDING); + if (rsize > nb) { /* Fail if wraps around zero */ + char* mp = (char*)(CALL_MMAP(rsize)); + if (mp != CMFAIL) { + tbase = mp; + tsize = rsize; + mmap_flag = IS_MMAPPED_BIT; + } + } + } + + if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ + size_t asize = granularity_align(nb + SYS_ALLOC_PADDING); + if (asize < HALF_MAX_SIZE_T) { + char* br = CMFAIL; + char* end = CMFAIL; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + br = (char*)(CALL_MORECORE(asize)); + end = (char*)(CALL_MORECORE(0)); + RELEASE_MALLOC_GLOBAL_LOCK(); + if (br != CMFAIL && end != CMFAIL && br < end) { + size_t ssize = end - br; + if (ssize > nb + TOP_FOOT_SIZE) { + tbase = br; + tsize = ssize; + } + } + } + } + + if (tbase != CMFAIL) { + + if ((m->footprint += tsize) > m->max_footprint) + m->max_footprint = m->footprint; + + if (!is_initialized(m)) { /* first-time initialization */ + m->seg.base = m->least_addr = tbase; + m->seg.size = tsize; + m->seg.sflags = mmap_flag; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + init_bins(m); +#if !ONLY_MSPACES + if (is_global(m)) + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + else +#endif + { + /* Offset top by embedded malloc_state */ + mchunkptr mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); + } + } + + else { + /* Try to merge with an existing segment */ + msegmentptr sp = &m->seg; + /* Only consider most recent segment if traversal suppressed */ + while (sp != 0 && tbase != sp->base + sp->size) + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & IS_MMAPPED_BIT) == mmap_flag && + segment_holds(sp, m->top)) { /* append */ + sp->size += tsize; + init_top(m, m->top, m->topsize + tsize); + } + else { + if (tbase < m->least_addr) + m->least_addr = tbase; + sp = &m->seg; + while (sp != 0 && sp->base != tbase + tsize) + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) { + char* oldbase = sp->base; + sp->base = tbase; + sp->size += tsize; + return prepend_alloc(m, tbase, oldbase, nb); + } + else + add_segment(m, tbase, tsize, mmap_flag); + } + } + + if (nb < m->topsize) { /* Allocate from new or extended top space */ + size_t rsize = m->topsize -= nb; + mchunkptr p = m->top; + mchunkptr r = m->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + check_top_chunk(m, m->top); + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); + } + } + + MALLOC_FAILURE_ACTION; + return 0; +} + +/* ----------------------- system deallocation -------------------------- */ + +/* Unmap and unlink any mmapped segments that don't contain used chunks */ +static size_t release_unused_segments(mstate m) { + size_t released = 0; + int nsegs = 0; + msegmentptr pred = &m->seg; + msegmentptr sp = pred->next; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + msegmentptr next = sp->next; + ++nsegs; + if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { + mchunkptr p = align_as_chunk(base); + size_t psize = chunksize(p); + /* Can unmap if first chunk holds entire segment and not pinned */ + if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { + tchunkptr tp = (tchunkptr)p; + assert(segment_holds(sp, (char*)sp)); + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + else { + unlink_large_chunk(m, tp); + } + if (CALL_MUNMAP(base, size) == 0) { + released += size; + m->footprint -= size; + /* unlink obsoleted record */ + sp = pred; + sp->next = next; + } + else { /* back out if cannot unmap */ + insert_large_chunk(m, tp, psize); + } + } + } + if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ + break; + pred = sp; + sp = next; + } + /* Reset check counter */ + m->release_checks = ((nsegs > MAX_RELEASE_CHECK_RATE)? + nsegs : MAX_RELEASE_CHECK_RATE); + return released; +} + +static int sys_trim(mstate m, size_t pad) { + size_t released = 0; + ensure_initialization(); + if (pad < MAX_REQUEST && is_initialized(m)) { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->topsize > pad) { + /* Shrink top space in granularity-size units, keeping at least one */ + size_t unit = mparams.granularity; + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char*)m->top); + + if (!is_extern_segment(sp)) { + if (is_mmapped_segment(sp)) { + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) { /* can't shrink if pinned */ + size_t newsize = sp->size - extra; + /* Prefer mremap, fall back to munmap */ + if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + released = extra; + } + } + } + else if (HAVE_MORECORE) { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + { + /* Make sure end of memory is where we last set it. */ + char* old_br = (char*)(CALL_MORECORE(0)); + if (old_br == sp->base + sp->size) { + char* rel_br = (char*)(CALL_MORECORE(-extra)); + char* new_br = (char*)(CALL_MORECORE(0)); + if (rel_br != CMFAIL && new_br < old_br) + released = old_br - new_br; + } + } + RELEASE_MALLOC_GLOBAL_LOCK(); + } + } + + if (released != 0) { + sp->size -= released; + m->footprint -= released; + init_top(m, m->top, m->topsize - released); + check_top_chunk(m, m->top); + } + } + + /* Unmap any unused mmapped segments */ + if (HAVE_MMAP) + released += release_unused_segments(m); + + /* On failure, disable autotrim to avoid repeated failed future calls */ + if (released == 0 && m->topsize > m->trim_check) + m->trim_check = MAX_SIZE_T; + } + + return (released != 0)? 1 : 0; +} + + +/* ---------------------------- malloc support --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +static void* tmalloc_large(mstate m, size_t nb) { + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + compute_tree_index(nb, idx); + if ((t = *treebin_at(m, idx)) != 0) { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + for (;;) { + tchunkptr rt; + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + v = t; + if ((rsize = trem) == 0) + break; + } + rt = t->child[1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; + if (t == 0) { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + sizebits <<= 1; + } + } + if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ + binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; + if (leftbits != 0) { + bindex_t i; + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + t = *treebin_at(m, i); + } + } + + while (t != 0) { /* find smallest of tree or subtree */ + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + t = leftmost_child(t); + } + + /* If dv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { + if (RTCHECK(ok_address(m, v))) { /* split */ + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + insert_chunk(m, r, rsize); + } + return chunk2mem(v); + } + } + CORRUPTION_ERROR_ACTION(m); + } + return 0; +} + +/* allocate a small request from the best fitting chunk in a treebin */ +static void* tmalloc_small(mstate m, size_t nb) { + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); + compute_bit2idx(leastbit, i); + v = t = *treebin_at(m, i); + rsize = chunksize(t) - nb; + + while ((t = leftmost_child(t)) != 0) { + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + } + + if (RTCHECK(ok_address(m, v))) { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(m, r, rsize); + } + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + return 0; +} + +/* --------------------------- realloc support --------------------------- */ + +static void* internal_realloc(mstate m, void* oldmem, size_t bytes) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + return 0; + } + if (!PREACTION(m)) { + mchunkptr oldp = mem2chunk(oldmem); + size_t oldsize = chunksize(oldp); + mchunkptr next = chunk_plus_offset(oldp, oldsize); + mchunkptr newp = 0; + void* extra = 0; + + /* Try to either shrink or extend into top. Else malloc-copy-free */ + + if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) && + ok_next(oldp, next) && ok_pinuse(next))) { + size_t nb = request2size(bytes); + if (is_mmapped(oldp)) + newp = mmap_resize(m, oldp, nb); + else if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + newp = oldp; + if (rsize >= MIN_CHUNK_SIZE) { + mchunkptr remainder = chunk_plus_offset(newp, nb); + set_inuse(m, newp, nb); + set_inuse(m, remainder, rsize); + extra = chunk2mem(remainder); + } + } + else if (next == m->top && oldsize + m->topsize > nb) { + /* Expand into top */ + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(oldp, nb); + set_inuse(m, oldp, nb); + newtop->head = newtopsize |PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = oldp; + } + } + else { + USAGE_ERROR_ACTION(m, oldmem); + POSTACTION(m); + return 0; + } + + POSTACTION(m); + + if (newp != 0) { + if (extra != 0) { + internal_free(m, extra); + } + check_inuse_chunk(m, newp); + return chunk2mem(newp); + } + else { + void* newmem = internal_malloc(m, bytes); + if (newmem != 0) { + size_t oc = oldsize - overhead_for(oldp); + memcpy(newmem, oldmem, (oc < bytes)? oc : bytes); + internal_free(m, oldmem); + } + return newmem; + } + } + return 0; +} + +/* --------------------------- memalign support -------------------------- */ + +static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { + if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */ + return internal_malloc(m, bytes); + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ + alignment = MIN_CHUNK_SIZE; + if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ + size_t a = MALLOC_ALIGNMENT << 1; + while (a < alignment) a <<= 1; + alignment = a; + } + + if (bytes >= MAX_REQUEST - alignment) { + if (m != 0) { /* Test isn't needed but avoids compiler warning */ + MALLOC_FAILURE_ACTION; + } + } + else { + size_t nb = request2size(bytes); + size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; + char* mem = (char*)internal_malloc(m, req); + if (mem != 0) { + void* leader = 0; + void* trailer = 0; + mchunkptr p = mem2chunk(mem); + + if (PREACTION(m)) return 0; + if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */ + /* + Find an aligned spot inside chunk. Since we need to give + back leading space in a chunk of at least MIN_CHUNK_SIZE, if + the first calculation places us at a spot with less than + MIN_CHUNK_SIZE leader, we can move to the next aligned spot. + We've allocated enough total room so that this is always + possible. + */ + char* br = (char*)mem2chunk((size_t)(((size_t)(mem + + alignment - + SIZE_T_ONE)) & + -alignment)); + char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? + br : br+alignment; + mchunkptr newp = (mchunkptr)pos; + size_t leadsize = pos - (char*)(p); + size_t newsize = chunksize(p) - leadsize; + + if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ + newp->prev_foot = p->prev_foot + leadsize; + newp->head = (newsize|CINUSE_BIT); + } + else { /* Otherwise, give back leader, use the rest */ + set_inuse(m, newp, newsize); + set_inuse(m, p, leadsize); + leader = chunk2mem(p); + } + p = newp; + } + + /* Give back spare room at the end */ + if (!is_mmapped(p)) { + size_t size = chunksize(p); + if (size > nb + MIN_CHUNK_SIZE) { + size_t remainder_size = size - nb; + mchunkptr remainder = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, remainder, remainder_size); + trailer = chunk2mem(remainder); + } + } + + assert (chunksize(p) >= nb); + assert((((size_t)(chunk2mem(p))) % alignment) == 0); + check_inuse_chunk(m, p); + POSTACTION(m); + if (leader != 0) { + internal_free(m, leader); + } + if (trailer != 0) { + internal_free(m, trailer); + } + return chunk2mem(p); + } + } + return 0; +} + +/* ------------------------ comalloc/coalloc support --------------------- */ + +static void** ialloc(mstate m, + size_t n_elements, + size_t* sizes, + int opts, + void* chunks[]) { + /* + This provides common support for independent_X routines, handling + all of the combinations that can result. + + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed + */ + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t i; + + ensure_initialization(); + /* compute array length, if needed */ + if (chunks != 0) { + if (n_elements == 0) + return chunks; /* nothing to do */ + marray = chunks; + array_size = 0; + } + else { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + return (void**)internal_malloc(m, 0); + marray = 0; + array_size = request2size(n_elements * (sizeof(void*))); + } + + /* compute total element size */ + if (opts & 0x1) { /* all-same-size */ + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else { /* add up all the sizes */ + element_size = 0; + contents_size = 0; + for (i = 0; i != n_elements; ++i) + contents_size += request2size(sizes[i]); + } + + size = contents_size + array_size; + + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + mem = internal_malloc(m, size - CHUNK_OVERHEAD); + if (was_enabled) + enable_mmap(m); + if (mem == 0) + return 0; + + if (PREACTION(m)) return 0; + p = mem2chunk(mem); + remainder_size = chunksize(p); + + assert(!is_mmapped(p)); + + if (opts & 0x2) { /* optionally clear the elements */ + memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) { + size_t array_chunk_size; + array_chunk = chunk_plus_offset(p, contents_size); + array_chunk_size = remainder_size - contents_size; + marray = (void**) (chunk2mem(array_chunk)); + set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) { + marray[i] = chunk2mem(p); + if (i != n_elements-1) { + if (element_size != 0) + size = element_size; + else + size = request2size(sizes[i]); + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + } + else { /* the final element absorbs any overallocation slop */ + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + break; + } + } + +#if DEBUG + if (marray != chunks) { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) { + assert(remainder_size == element_size); + } + else { + assert(remainder_size == request2size(sizes[i])); + } + check_inuse_chunk(m, mem2chunk(marray)); + } + for (i = 0; i != n_elements; ++i) + check_inuse_chunk(m, mem2chunk(marray[i])); + +#endif /* DEBUG */ + + POSTACTION(m); + return marray; +} + + +/* -------------------------- public routines ---------------------------- */ + +#if !ONLY_MSPACES + +void* dlmalloc(size_t bytes) { + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the dv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in dv. + 4. If it is big enough, use the top chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than dv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the dv chunk. + 3. If it is big enough, use the top chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it + + The ugly goto's here ensure that postaction occurs along all paths. + */ + +#if USE_LOCKS + ensure_initialization(); /* initialize in sys_alloc if not using locks */ +#endif + + if (!PREACTION(gm)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = gm->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(gm, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(gm, b, p, idx); + set_inuse_and_pinuse(gm, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb > gm->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(gm, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(gm, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(gm, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(gm, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + + if (nb <= gm->dvsize) { + size_t rsize = gm->dvsize - nb; + mchunkptr p = gm->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = gm->dv = chunk_plus_offset(p, nb); + gm->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + } + else { /* exhaust dv */ + size_t dvs = gm->dvsize; + gm->dvsize = 0; + gm->dv = 0; + set_inuse_and_pinuse(gm, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb < gm->topsize) { /* Split top */ + size_t rsize = gm->topsize -= nb; + mchunkptr p = gm->top; + mchunkptr r = gm->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + mem = chunk2mem(p); + check_top_chunk(gm, gm->top); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + mem = sys_alloc(gm, nb); + + postaction: + POSTACTION(gm); + return mem; + } + + return 0; +} + +void dlfree(void* mem) { + /* + Consolidate freed chunks with preceeding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for top, dv, mmapped chunks, and usage errors. + */ + + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ +} + +void* dlcalloc(size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = dlmalloc(req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* dlrealloc(void* oldmem, size_t bytes) { + if (oldmem == 0) + return dlmalloc(bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + dlfree(oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(mem2chunk(oldmem)); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + return internal_realloc(m, oldmem, bytes); + } +} + +void* dlmemalign(size_t alignment, size_t bytes) { + return internal_memalign(gm, alignment, bytes); +} + +void** dlindependent_calloc(size_t n_elements, size_t elem_size, + void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + return ialloc(gm, n_elements, &sz, 3, chunks); +} + +void** dlindependent_comalloc(size_t n_elements, size_t sizes[], + void* chunks[]) { + return ialloc(gm, n_elements, sizes, 0, chunks); +} + +void* dlvalloc(size_t bytes) { + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, bytes); +} + +void* dlpvalloc(size_t bytes) { + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); +} + +int dlmalloc_trim(size_t pad) { + ensure_initialization(); + int result = 0; + if (!PREACTION(gm)) { + result = sys_trim(gm, pad); + POSTACTION(gm); + } + return result; +} + +size_t dlmalloc_footprint(void) { + return gm->footprint; +} + +size_t dlmalloc_max_footprint(void) { + return gm->max_footprint; +} + +#if !NO_MALLINFO +struct mallinfo dlmallinfo(void) { + return internal_mallinfo(gm); +} +#endif /* NO_MALLINFO */ + +void dlmalloc_stats() { + internal_malloc_stats(gm); +} + +int dlmallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* !ONLY_MSPACES */ + +size_t dlmalloc_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (cinuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +/* ----------------------------- user mspaces ---------------------------- */ + +#if MSPACES + +static mstate init_user_mstate(char* tbase, size_t tsize) { + size_t msize = pad_request(sizeof(struct malloc_state)); + mchunkptr mn; + mchunkptr msp = align_as_chunk(tbase); + mstate m = (mstate)(chunk2mem(msp)); + memset(m, 0, msize); + INITIAL_LOCK(&m->mutex); + msp->head = (msize|PINUSE_BIT|CINUSE_BIT); + m->seg.base = m->least_addr = tbase; + m->seg.size = m->footprint = m->max_footprint = tsize; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + m->mflags = mparams.default_mflags; + m->extp = 0; + m->exts = 0; + disable_contiguous(m); + init_bins(m); + mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); + check_top_chunk(m, m->top); + return m; +} + +mspace create_mspace(size_t capacity, int locked) { + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + size_t rs = ((capacity == 0)? mparams.granularity : + (capacity + TOP_FOOT_SIZE + msize)); + size_t tsize = granularity_align(rs); + char* tbase = (char*)(CALL_MMAP(tsize)); + if (tbase != CMFAIL) { + m = init_user_mstate(tbase, tsize); + m->seg.sflags = IS_MMAPPED_BIT; + set_lock(m, locked); + } + } + return (mspace)m; +} + +mspace create_mspace_with_base(void* base, size_t capacity, int locked) { + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + if (capacity > msize + TOP_FOOT_SIZE && + capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + m = init_user_mstate((char*)base, capacity); + m->seg.sflags = EXTERN_BIT; + set_lock(m, locked); + } + return (mspace)m; +} + +int mspace_mmap_large_chunks(mspace msp, int enable) { + int ret = 0; + mstate ms = (mstate)msp; + if (!PREACTION(ms)) { + if (use_mmap(ms)) + ret = 1; + if (enable) + enable_mmap(ms); + else + disable_mmap(ms); + POSTACTION(ms); + } + return ret; +} + +size_t destroy_mspace(mspace msp) { + size_t freed = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + msegmentptr sp = &ms->seg; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + flag_t flag = sp->sflags; + sp = sp->next; + if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) && + CALL_MUNMAP(base, size) == 0) + freed += size; + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return freed; +} + +/* + mspace versions of routines are near-clones of the global + versions. This is not so nice but better than the alternatives. +*/ + + +void* mspace_malloc(mspace msp, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (!PREACTION(ms)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = ms->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(ms, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(ms, b, p, idx); + set_inuse_and_pinuse(ms, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb > ms->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(ms, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(ms, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(ms, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(ms, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + + if (nb <= ms->dvsize) { + size_t rsize = ms->dvsize - nb; + mchunkptr p = ms->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = ms->dv = chunk_plus_offset(p, nb); + ms->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + } + else { /* exhaust dv */ + size_t dvs = ms->dvsize; + ms->dvsize = 0; + ms->dv = 0; + set_inuse_and_pinuse(ms, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb < ms->topsize) { /* Split top */ + size_t rsize = ms->topsize -= nb; + mchunkptr p = ms->top; + mchunkptr r = ms->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + mem = chunk2mem(p); + check_top_chunk(ms, ms->top); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + mem = sys_alloc(ms, nb); + + postaction: + POSTACTION(ms); + return mem; + } + + return 0; +} + +void mspace_free(mspace msp, void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +} + +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = internal_malloc(ms, req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { + if (oldmem == 0) + return mspace_malloc(msp, bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + mspace_free(msp, oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if FOOTERS + mchunkptr p = mem2chunk(oldmem); + mstate ms = get_mstate_for(p); +#else /* FOOTERS */ + mstate ms = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return internal_realloc(ms, oldmem, bytes); + } +} + +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return internal_memalign(ms, alignment, bytes); +} + +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, &sz, 3, chunks); +} + +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, sizes, 0, chunks); +} + +int mspace_trim(mspace msp, size_t pad) { + int result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (!PREACTION(ms)) { + result = sys_trim(ms, pad); + POSTACTION(ms); + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +void mspace_malloc_stats(mspace msp) { + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + internal_malloc_stats(ms); + } + else { + USAGE_ERROR_ACTION(ms,ms); + } +} + +size_t mspace_footprint(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->footprint; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + + +size_t mspace_max_footprint(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->max_footprint; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + + +#if !NO_MALLINFO +struct mallinfo mspace_mallinfo(mspace msp) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + return internal_mallinfo(ms); +} +#endif /* NO_MALLINFO */ + +size_t mspace_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (cinuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +int mspace_mallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* MSPACES */ + +/* -------------------- Alternative MORECORE functions ------------------- */ + +/* + Guidelines for creating a custom version of MORECORE: + + * For best performance, MORECORE should allocate in multiples of pagesize. + * MORECORE may allocate more memory than requested. (Or even less, + but this will usually result in a malloc failure.) + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. + * For best performance, consecutive calls to MORECORE with positive + arguments should return increasing addresses, indicating that + space has been contiguously extended. + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + * MORECORE need not handle negative arguments -- it may instead + just return MFAIL when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + As an example alternative MORECORE, here is a custom allocator + kindly contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024U) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MFAIL; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MFAIL; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* ----------------------------------------------------------------------- +History: + V2.8.4 (not yet released) + * Add mspace_mmap_large_chunks; thanks to Jean Brouwers + * Fix insufficient sys_alloc padding when using 16byte alignment + * Fix bad error check in mspace_footprint + * Adaptations for ptmalloc, courtesy of Wolfram Gloger. + * Reentrant spin locks, courtesy of Earl Chew and others + * Win32 improvements, courtesy of Niall Douglas and Earl Chew + * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options + * Extension hook in malloc_state + * Various small adjustments to reduce warnings on some compilers + * Various configuration extensions/changes for more platforms. Thanks + to all who contributed these. + + V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) + * Add max_footprint functions + * Ensure all appropriate literals are size_t + * Fix conditional compilation problem for some #define settings + * Avoid concatenating segments with the one provided + in create_mspace_with_base + * Rename some variables to avoid compiler shadowing warnings + * Use explicit lock initialization. + * Better handling of sbrk interference. + * Simplify and fix segment insertion, trimming and mspace_destroy + * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x + * Thanks especially to Dennis Flanagan for help on these. + + V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) + * Fix memalign brace error. + + V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) + * Fix improper #endif nesting in C++ + * Add explicit casts needed for C++ + + V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) + * Use trees for large bins + * Support mspaces + * Use segments to unify sbrk-based and mmap-based system allocation, + removing need for emulation on most platforms without sbrk. + * Default safety checks + * Optional footer checks. Thanks to William Robertson for the idea. + * Internal code refactoring + * Incorporate suggestions and platform-specific changes. + Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, + Aaron Bachmann, Emery Berger, and others. + * Speed up non-fastbin processing enough to remove fastbins. + * Remove useless cfree() to avoid conflicts with other apps. + * Remove internal memcpy, memset. Compilers handle builtins better. + * Remove some options that no one ever used and rename others. + + V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) + * Fix malloc_state bitmap array misdeclaration + + V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) + * Allow tuning of FIRST_SORTED_BIN_SIZE + * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. + * Better detection and support for non-contiguousness of MORECORE. + Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger + * Bypass most of malloc if no frees. Thanks To Emery Berger. + * Fix freeing of old top non-contiguous chunk im sysmalloc. + * Raised default trim and map thresholds to 256K. + * Fix mmap-related #defines. Thanks to Lubos Lunak. + * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. + * Branch-free bin calculation + * Default trim and mmap thresholds now 256K. + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from . + Thanks also to Andreas Mueller , + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sysmalloc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ + + diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c new file mode 100644 index 0000000000..a381a7df36 --- /dev/null +++ b/compat/nedmalloc/nedmalloc.c @@ -0,0 +1,966 @@ +/* Alternative malloc implementation for multiple threads without +lock contention based on dlmalloc. (C) 2005-2006 Niall Douglas + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#ifdef _MSC_VER +/* Enable full aliasing on MSVC */ +/*#pragma optimize("a", on)*/ +#endif + +/*#define FULLSANITYCHECKS*/ + +#include "nedmalloc.h" +#if defined(WIN32) && !defined(__MINGW32__) + #include +#endif +#define MSPACES 1 +#define ONLY_MSPACES 1 +#ifndef USE_LOCKS + #define USE_LOCKS 1 +#endif +#define FOOTERS 1 /* Need to enable footers so frees lock the right mspace */ +#undef DEBUG /* dlmalloc wants DEBUG either 0 or 1 */ +#ifdef _DEBUG + #define DEBUG 1 +#else + #define DEBUG 0 +#endif +#ifdef NDEBUG /* Disable assert checking on release builds */ + #undef DEBUG +#endif +/* The default of 64Kb means we spend too much time kernel-side */ +#ifndef DEFAULT_GRANULARITY +#define DEFAULT_GRANULARITY (1*1024*1024) +#endif +/*#define USE_SPIN_LOCKS 0*/ + + +/*#define FORCEINLINE*/ +#include "malloc.c.h" +#ifdef NDEBUG /* Disable assert checking on release builds */ + #undef DEBUG +#endif + +/* The maximum concurrent threads in a pool possible */ +#ifndef MAXTHREADSINPOOL +#define MAXTHREADSINPOOL 16 +#endif +/* The maximum number of threadcaches which can be allocated */ +#ifndef THREADCACHEMAXCACHES +#define THREADCACHEMAXCACHES 256 +#endif +/* The maximum size to be allocated from the thread cache */ +#ifndef THREADCACHEMAX +#define THREADCACHEMAX 8192 +#endif +#if 0 +/* The number of cache entries for finer grained bins. This is (topbitpos(THREADCACHEMAX)-4)*2 */ +#define THREADCACHEMAXBINS ((13-4)*2) +#else +/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */ +#define THREADCACHEMAXBINS (13-4) +#endif +/* Point at which the free space in a thread cache is garbage collected */ +#ifndef THREADCACHEMAXFREESPACE +#define THREADCACHEMAXFREESPACE (512*1024) +#endif + + +#ifdef WIN32 + #define TLSVAR DWORD + #define TLSALLOC(k) (*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k)) + #define TLSFREE(k) (!TlsFree(k)) + #define TLSGET(k) TlsGetValue(k) + #define TLSSET(k, a) (!TlsSetValue(k, a)) + #ifdef DEBUG +static LPVOID ChkedTlsGetValue(DWORD idx) +{ + LPVOID ret=TlsGetValue(idx); + assert(S_OK==GetLastError()); + return ret; +} + #undef TLSGET + #define TLSGET(k) ChkedTlsGetValue(k) + #endif +#else + #define TLSVAR pthread_key_t + #define TLSALLOC(k) pthread_key_create(k, 0) + #define TLSFREE(k) pthread_key_delete(k) + #define TLSGET(k) pthread_getspecific(k) + #define TLSSET(k, a) pthread_setspecific(k, a) +#endif + +#if 0 +/* Only enable if testing with valgrind. Causes misoperation */ +#define mspace_malloc(p, s) malloc(s) +#define mspace_realloc(p, m, s) realloc(m, s) +#define mspace_calloc(p, n, s) calloc(n, s) +#define mspace_free(p, m) free(m) +#endif + + +#if defined(__cplusplus) +#if !defined(NO_NED_NAMESPACE) +namespace nedalloc { +#else +extern "C" { +#endif +#endif + +size_t nedblksize(void *mem) THROWSPEC +{ +#if 0 + /* Only enable if testing with valgrind. Causes misoperation */ + return THREADCACHEMAX; +#else + if(mem) + { + mchunkptr p=mem2chunk(mem); + assert(cinuse(p)); /* If this fails, someone tried to free a block twice */ + if(cinuse(p)) + return chunksize(p)-overhead_for(p); + } + return 0; +#endif +} + +void nedsetvalue(void *v) THROWSPEC { nedpsetvalue(0, v); } +void * nedmalloc(size_t size) THROWSPEC { return nedpmalloc(0, size); } +void * nedcalloc(size_t no, size_t size) THROWSPEC { return nedpcalloc(0, no, size); } +void * nedrealloc(void *mem, size_t size) THROWSPEC { return nedprealloc(0, mem, size); } +void nedfree(void *mem) THROWSPEC { nedpfree(0, mem); } +void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign(0, alignment, bytes); } +#if !NO_MALLINFO +struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); } +#endif +int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); } +int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); } +void nedmalloc_stats() THROWSPEC { nedpmalloc_stats(0); } +size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint(0); } +void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); } +void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); } + +struct threadcacheblk_t; +typedef struct threadcacheblk_t threadcacheblk; +struct threadcacheblk_t +{ /* Keep less than 16 bytes on 32 bit systems and 32 bytes on 64 bit systems */ +#ifdef FULLSANITYCHECKS + unsigned int magic; +#endif + unsigned int lastUsed, size; + threadcacheblk *next, *prev; +}; +typedef struct threadcache_t +{ +#ifdef FULLSANITYCHECKS + unsigned int magic1; +#endif + int mymspace; /* Last mspace entry this thread used */ + long threadid; + unsigned int mallocs, frees, successes; + size_t freeInCache; /* How much free space is stored in this cache */ + threadcacheblk *bins[(THREADCACHEMAXBINS+1)*2]; +#ifdef FULLSANITYCHECKS + unsigned int magic2; +#endif +} threadcache; +struct nedpool_t +{ + MLOCK_T mutex; + void *uservalue; + int threads; /* Max entries in m to use */ + threadcache *caches[THREADCACHEMAXCACHES]; + TLSVAR mycache; /* Thread cache for this thread. 0 for unset, negative for use mspace-1 directly, otherwise is cache-1 */ + mstate m[MAXTHREADSINPOOL+1]; /* mspace entries for this pool */ +}; +static nedpool syspool; + +static FORCEINLINE unsigned int size2binidx(size_t _size) THROWSPEC +{ /* 8=1000 16=10000 20=10100 24=11000 32=100000 48=110000 4096=1000000000000 */ + unsigned int topbit, size=(unsigned int)(_size>>4); + /* 16=1 20=1 24=1 32=10 48=11 64=100 96=110 128=1000 4096=100000000 */ + +#if defined(__GNUC__) + topbit = sizeof(size)*__CHAR_BIT__ - 1 - __builtin_clz(size); +#elif defined(_MSC_VER) && _MSC_VER>=1300 + { + unsigned long bsrTopBit; + + _BitScanReverse(&bsrTopBit, size); + + topbit = bsrTopBit; + } +#else +#if 0 + union { + unsigned asInt[2]; + double asDouble; + }; + int n; + + asDouble = (double)size + 0.5; + topbit = (asInt[!FOX_BIGENDIAN] >> 20) - 1023; +#else + { + unsigned int x=size; + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >>16); + x = ~x; + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x << 8); + x = x + (x << 16); + topbit=31 - (x >> 24); + } +#endif +#endif + return topbit; +} + + +#ifdef FULLSANITYCHECKS +static void tcsanitycheck(threadcacheblk **ptr) THROWSPEC +{ + assert((ptr[0] && ptr[1]) || (!ptr[0] && !ptr[1])); + if(ptr[0] && ptr[1]) + { + assert(nedblksize(ptr[0])>=sizeof(threadcacheblk)); + assert(nedblksize(ptr[1])>=sizeof(threadcacheblk)); + assert(*(unsigned int *) "NEDN"==ptr[0]->magic); + assert(*(unsigned int *) "NEDN"==ptr[1]->magic); + assert(!ptr[0]->prev); + assert(!ptr[1]->next); + if(ptr[0]==ptr[1]) + { + assert(!ptr[0]->next); + assert(!ptr[1]->prev); + } + } +} +static void tcfullsanitycheck(threadcache *tc) THROWSPEC +{ + threadcacheblk **tcbptr=tc->bins; + int n; + for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2) + { + threadcacheblk *b, *ob=0; + tcsanitycheck(tcbptr); + for(b=tcbptr[0]; b; ob=b, b=b->next) + { + assert(*(unsigned int *) "NEDN"==b->magic); + assert(!ob || ob->next==b); + assert(!ob || b->prev==ob); + } + } +} +#endif + +static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC +{ +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif + if(tc->freeInCache) + { + threadcacheblk **tcbptr=tc->bins; + int n; + for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2) + { + threadcacheblk **tcb=tcbptr+1; /* come from oldest end of list */ + /*tcsanitycheck(tcbptr);*/ + for(; *tcb && tc->frees-(*tcb)->lastUsed>=age; ) + { + threadcacheblk *f=*tcb; + size_t blksize=f->size; /*nedblksize(f);*/ + assert(blksize<=nedblksize(f)); + assert(blksize); +#ifdef FULLSANITYCHECKS + assert(*(unsigned int *) "NEDN"==(*tcb)->magic); +#endif + *tcb=(*tcb)->prev; + if(*tcb) + (*tcb)->next=0; + else + *tcbptr=0; + tc->freeInCache-=blksize; + assert((long) tc->freeInCache>=0); + mspace_free(0, f); + /*tcsanitycheck(tcbptr);*/ + } + } + } +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif +} +static void DestroyCaches(nedpool *p) THROWSPEC +{ + if(p->caches) + { + threadcache *tc; + int n; + for(n=0; ncaches[n])) + { + tc->frees++; + RemoveCacheEntries(p, tc, 0); + assert(!tc->freeInCache); + tc->mymspace=-1; + tc->threadid=0; + mspace_free(0, tc); + p->caches[n]=0; + } + } + } +} + +static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC +{ + threadcache *tc=0; + int n, end; + ACQUIRE_LOCK(&p->mutex); + for(n=0; ncaches[n]; n++); + if(THREADCACHEMAXCACHES==n) + { /* List exhausted, so disable for this thread */ + RELEASE_LOCK(&p->mutex); + return 0; + } + tc=p->caches[n]=(threadcache *) mspace_calloc(p->m[0], 1, sizeof(threadcache)); + if(!tc) + { + RELEASE_LOCK(&p->mutex); + return 0; + } +#ifdef FULLSANITYCHECKS + tc->magic1=*(unsigned int *)"NEDMALC1"; + tc->magic2=*(unsigned int *)"NEDMALC2"; +#endif + tc->threadid=(long)(size_t)CURRENT_THREAD; + for(end=0; p->m[end]; end++); + tc->mymspace=tc->threadid % end; + RELEASE_LOCK(&p->mutex); + if(TLSSET(p->mycache, (void *)(size_t)(n+1))) abort(); + return tc; +} + +static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROWSPEC +{ + void *ret=0; + unsigned int bestsize; + unsigned int idx=size2binidx(*size); + size_t blksize=0; + threadcacheblk *blk, **binsptr; +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif + /* Calculate best fit bin size */ + bestsize=1<<(idx+4); +#if 0 + /* Finer grained bin fit */ + idx<<=1; + if(*size>bestsize) + { + idx++; + bestsize+=bestsize>>1; + } + if(*size>bestsize) + { + idx++; + bestsize=1<<(4+(idx>>1)); + } +#else + if(*size>bestsize) + { + idx++; + bestsize<<=1; + } +#endif + assert(bestsize>=*size); + if(*sizebins[idx*2]; + /* Try to match close, but move up a bin if necessary */ + blk=*binsptr; + if(!blk || blk->size<*size) + { /* Bump it up a bin */ + if(idxsize; /*nedblksize(blk);*/ + assert(nedblksize(blk)>=blksize); + assert(blksize>=*size); + if(blk->next) + blk->next->prev=0; + *binsptr=blk->next; + if(!*binsptr) + binsptr[1]=0; +#ifdef FULLSANITYCHECKS + blk->magic=0; +#endif + assert(binsptr[0]!=blk && binsptr[1]!=blk); + assert(nedblksize(blk)>=sizeof(threadcacheblk) && nedblksize(blk)<=THREADCACHEMAX+CHUNK_OVERHEAD); + /*printf("malloc: %p, %p, %p, %lu\n", p, tc, blk, (long) size);*/ + ret=(void *) blk; + } + ++tc->mallocs; + if(ret) + { + assert(blksize>=*size); + ++tc->successes; + tc->freeInCache-=blksize; + assert((long) tc->freeInCache>=0); + } +#if defined(DEBUG) && 0 + if(!(tc->mallocs & 0xfff)) + { + printf("*** threadcache=%u, mallocs=%u (%f), free=%u (%f), freeInCache=%u\n", (unsigned int) tc->threadid, tc->mallocs, + (float) tc->successes/tc->mallocs, tc->frees, (float) tc->successes/tc->frees, (unsigned int) tc->freeInCache); + } +#endif +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif + return ret; +} +static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspace) THROWSPEC +{ + unsigned int age=THREADCACHEMAXFREESPACE/8192; + /*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/ + while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE) + { + RemoveCacheEntries(p, tc, age); + /*printf("*** Removing cache entries older than %u (%u)\n", age, (unsigned int) tc->freeInCache);*/ + age>>=1; + } + /*RELEASE_LOCK(&p->m[mymspace]->mutex);*/ +} +static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *mem, size_t size) THROWSPEC +{ + unsigned int bestsize; + unsigned int idx=size2binidx(size); + threadcacheblk **binsptr, *tck=(threadcacheblk *) mem; + assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD); +#ifdef DEBUG + { /* Make sure this is a valid memory block */ + mchunkptr p = mem2chunk(mem); + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + } +#endif +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif + /* Calculate best fit bin size */ + bestsize=1<<(idx+4); +#if 0 + /* Finer grained bin fit */ + idx<<=1; + if(size>bestsize) + { + unsigned int biggerbestsize=bestsize+bestsize<<1; + if(size>=biggerbestsize) + { + idx++; + bestsize=biggerbestsize; + } + } +#endif + if(bestsize!=size) /* dlmalloc can round up, so we round down to preserve indexing */ + size=bestsize; + binsptr=&tc->bins[idx*2]; + assert(idx<=THREADCACHEMAXBINS); + if(tck==*binsptr) + { + fprintf(stderr, "Attempt to free already freed memory block %p - aborting!\n", tck); + abort(); + } +#ifdef FULLSANITYCHECKS + tck->magic=*(unsigned int *) "NEDN"; +#endif + tck->lastUsed=++tc->frees; + tck->size=(unsigned int) size; + tck->next=*binsptr; + tck->prev=0; + if(tck->next) + tck->next->prev=tck; + else + binsptr[1]=tck; + assert(!*binsptr || (*binsptr)->size==tck->size); + *binsptr=tck; + assert(tck==tc->bins[idx*2]); + assert(tc->bins[idx*2+1]==tck || binsptr[0]->next->prev==tck); + /*printf("free: %p, %p, %p, %lu\n", p, tc, mem, (long) size);*/ + tc->freeInCache+=size; +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif +#if 1 + if(tc->freeInCache>=THREADCACHEMAXFREESPACE) + ReleaseFreeInCache(p, tc, mymspace); +#endif +} + + + + +static NOINLINE int InitPool(nedpool *p, size_t capacity, int threads) THROWSPEC +{ /* threads is -1 for system pool */ + ensure_initialization(); + ACQUIRE_MALLOC_GLOBAL_LOCK(); + if(p->threads) goto done; + if(INITIAL_LOCK(&p->mutex)) goto err; + if(TLSALLOC(&p->mycache)) goto err; + if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err; + p->m[0]->extp=p; + p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads; +done: + RELEASE_MALLOC_GLOBAL_LOCK(); + return 1; +err: + if(threads<0) + abort(); /* If you can't allocate for system pool, we're screwed */ + DestroyCaches(p); + if(p->m[0]) + { + destroy_mspace(p->m[0]); + p->m[0]=0; + } + if(p->mycache) + { + if(TLSFREE(p->mycache)) abort(); + p->mycache=0; + } + RELEASE_MALLOC_GLOBAL_LOCK(); + return 0; +} +static NOINLINE mstate FindMSpace(nedpool *p, threadcache *tc, int *lastUsed, size_t size) THROWSPEC +{ /* Gets called when thread's last used mspace is in use. The strategy + is to run through the list of all available mspaces looking for an + unlocked one and if we fail, we create a new one so long as we don't + exceed p->threads */ + int n, end; + for(n=end=*lastUsed+1; p->m[n]; end=++n) + { + if(TRY_LOCK(&p->m[n]->mutex)) goto found; + } + for(n=0; n<*lastUsed && p->m[n]; n++) + { + if(TRY_LOCK(&p->m[n]->mutex)) goto found; + } + if(endthreads) + { + mstate temp; + if(!(temp=(mstate) create_mspace(size, 1))) + goto badexit; + /* Now we're ready to modify the lists, we lock */ + ACQUIRE_LOCK(&p->mutex); + while(p->m[end] && endthreads) + end++; + if(end>=p->threads) + { /* Drat, must destroy it now */ + RELEASE_LOCK(&p->mutex); + destroy_mspace((mspace) temp); + goto badexit; + } + /* We really want to make sure this goes into memory now but we + have to be careful of breaking aliasing rules, so write it twice */ + *((volatile struct malloc_state **) &p->m[end])=p->m[end]=temp; + ACQUIRE_LOCK(&p->m[end]->mutex); + /*printf("Created mspace idx %d\n", end);*/ + RELEASE_LOCK(&p->mutex); + n=end; + goto found; + } + /* Let it lock on the last one it used */ +badexit: + ACQUIRE_LOCK(&p->m[*lastUsed]->mutex); + return p->m[*lastUsed]; +found: + *lastUsed=n; + if(tc) + tc->mymspace=n; + else + { + if(TLSSET(p->mycache, (void *)(size_t)(-(n+1)))) abort(); + } + return p->m[n]; +} + +nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC +{ + nedpool *ret; + if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) return 0; + if(!InitPool(ret, capacity, threads)) + { + nedpfree(0, ret); + return 0; + } + return ret; +} +void neddestroypool(nedpool *p) THROWSPEC +{ + int n; + ACQUIRE_LOCK(&p->mutex); + DestroyCaches(p); + for(n=0; p->m[n]; n++) + { + destroy_mspace(p->m[n]); + p->m[n]=0; + } + RELEASE_LOCK(&p->mutex); + if(TLSFREE(p->mycache)) abort(); + nedpfree(0, p); +} + +void nedpsetvalue(nedpool *p, void *v) THROWSPEC +{ + if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } + p->uservalue=v; +} +void *nedgetvalue(nedpool **p, void *mem) THROWSPEC +{ + nedpool *np=0; + mchunkptr mcp=mem2chunk(mem); + mstate fm; + if(!(is_aligned(chunk2mem(mcp))) && mcp->head != FENCEPOST_HEAD) return 0; + if(!cinuse(mcp)) return 0; + if(!next_pinuse(mcp)) return 0; + if(!is_mmapped(mcp) && !pinuse(mcp)) + { + if(next_chunk(prev_chunk(mcp))!=mcp) return 0; + } + fm=get_mstate_for(mcp); + if(!ok_magic(fm)) return 0; + if(!ok_address(fm, mcp)) return 0; + if(!fm->extp) return 0; + np=(nedpool *) fm->extp; + if(p) *p=np; + return np->uservalue; +} + +void neddisablethreadcache(nedpool *p) THROWSPEC +{ + int mycache; + if(!p) + { + p=&syspool; + if(!syspool.threads) InitPool(&syspool, 0, -1); + } + mycache=(int)(size_t) TLSGET(p->mycache); + if(!mycache) + { /* Set to mspace 0 */ + if(TLSSET(p->mycache, (void *)-1)) abort(); + } + else if(mycache>0) + { /* Set to last used mspace */ + threadcache *tc=p->caches[mycache-1]; +#if defined(DEBUG) + printf("Threadcache utilisation: %lf%% in cache with %lf%% lost to other threads\n", + 100.0*tc->successes/tc->mallocs, 100.0*((double) tc->mallocs-tc->frees)/tc->mallocs); +#endif + if(TLSSET(p->mycache, (void *)(size_t)(-tc->mymspace))) abort(); + tc->frees++; + RemoveCacheEntries(p, tc, 0); + assert(!tc->freeInCache); + tc->mymspace=-1; + tc->threadid=0; + mspace_free(0, p->caches[mycache-1]); + p->caches[mycache-1]=0; + } +} + +#define GETMSPACE(m,p,tc,ms,s,action) \ + do \ + { \ + mstate m = GetMSpace((p),(tc),(ms),(s)); \ + action; \ + RELEASE_LOCK(&m->mutex); \ + } while (0) + +static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC +{ /* Returns a locked and ready for use mspace */ + mstate m=p->m[mymspace]; + assert(m); + if(!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size);\ + /*assert(IS_LOCKED(&p->m[mymspace]->mutex));*/ + return m; +} +static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymspace, size_t *size) THROWSPEC +{ + int mycache; + if(size && *sizemycache); + if(mycache>0) + { + *tc=(*p)->caches[mycache-1]; + *mymspace=(*tc)->mymspace; + } + else if(!mycache) + { + *tc=AllocCache(*p); + if(!*tc) + { /* Disable */ + if(TLSSET((*p)->mycache, (void *)-1)) abort(); + *mymspace=0; + } + else + *mymspace=(*tc)->mymspace; + } + else + { + *tc=0; + *mymspace=-mycache-1; + } + assert(*mymspace>=0); + assert((long)(size_t)CURRENT_THREAD==(*tc)->threadid); +#ifdef FULLSANITYCHECKS + if(*tc) + { + if(*(unsigned int *)"NEDMALC1"!=(*tc)->magic1 || *(unsigned int *)"NEDMALC2"!=(*tc)->magic2) + { + abort(); + } + } +#endif +} + +void * nedpmalloc(nedpool *p, size_t size) THROWSPEC +{ + void *ret=0; + threadcache *tc; + int mymspace; + GetThreadCache(&p, &tc, &mymspace, &size); +#if THREADCACHEMAX + if(tc && size<=THREADCACHEMAX) + { /* Use the thread cache */ + ret=threadcache_malloc(p, tc, &size); + } +#endif + if(!ret) + { /* Use this thread's mspace */ + GETMSPACE(m, p, tc, mymspace, size, + ret=mspace_malloc(m, size)); + } + return ret; +} +void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC +{ + size_t rsize=size*no; + void *ret=0; + threadcache *tc; + int mymspace; + GetThreadCache(&p, &tc, &mymspace, &rsize); +#if THREADCACHEMAX + if(tc && rsize<=THREADCACHEMAX) + { /* Use the thread cache */ + if((ret=threadcache_malloc(p, tc, &rsize))) + memset(ret, 0, rsize); + } +#endif + if(!ret) + { /* Use this thread's mspace */ + GETMSPACE(m, p, tc, mymspace, rsize, + ret=mspace_calloc(m, 1, rsize)); + } + return ret; +} +void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC +{ + void *ret=0; + threadcache *tc; + int mymspace; + if(!mem) return nedpmalloc(p, size); + GetThreadCache(&p, &tc, &mymspace, &size); +#if THREADCACHEMAX + if(tc && size && size<=THREADCACHEMAX) + { /* Use the thread cache */ + size_t memsize=nedblksize(mem); + assert(memsize); + if((ret=threadcache_malloc(p, tc, &size))) + { + memcpy(ret, mem, memsizem[n]; n++) + { + struct mallinfo t=mspace_mallinfo(p->m[n]); + ret.arena+=t.arena; + ret.ordblks+=t.ordblks; + ret.hblkhd+=t.hblkhd; + ret.usmblks+=t.usmblks; + ret.uordblks+=t.uordblks; + ret.fordblks+=t.fordblks; + ret.keepcost+=t.keepcost; + } + return ret; +} +#endif +int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC +{ + return mspace_mallopt(parno, value); +} +int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC +{ + int n, ret=0; + if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } + for(n=0; p->m[n]; n++) + { + ret+=mspace_trim(p->m[n], pad); + } + return ret; +} +void nedpmalloc_stats(nedpool *p) THROWSPEC +{ + int n; + if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } + for(n=0; p->m[n]; n++) + { + mspace_malloc_stats(p->m[n]); + } +} +size_t nedpmalloc_footprint(nedpool *p) THROWSPEC +{ + size_t ret=0; + int n; + if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } + for(n=0; p->m[n]; n++) + { + ret+=mspace_footprint(p->m[n]); + } + return ret; +} +void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC +{ + void **ret; + threadcache *tc; + int mymspace; + GetThreadCache(&p, &tc, &mymspace, &elemsize); + GETMSPACE(m, p, tc, mymspace, elemsno*elemsize, + ret=mspace_independent_calloc(m, elemsno, elemsize, chunks)); + return ret; +} +void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC +{ + void **ret; + threadcache *tc; + int mymspace; + size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t)); + if(!adjustedsizes) return 0; + for(i=0; i /* for size_t */ + +#ifndef EXTSPEC + #define EXTSPEC extern +#endif + +#if defined(_MSC_VER) && _MSC_VER>=1400 + #define MALLOCATTR __declspec(restrict) +#endif +#ifdef __GNUC__ + #define MALLOCATTR __attribute__ ((malloc)) +#endif +#ifndef MALLOCATTR + #define MALLOCATTR +#endif + +#ifdef REPLACE_SYSTEM_ALLOCATOR + #define nedmalloc malloc + #define nedcalloc calloc + #define nedrealloc realloc + #define nedfree free + #define nedmemalign memalign + #define nedmallinfo mallinfo + #define nedmallopt mallopt + #define nedmalloc_trim malloc_trim + #define nedmalloc_stats malloc_stats + #define nedmalloc_footprint malloc_footprint + #define nedindependent_calloc independent_calloc + #define nedindependent_comalloc independent_comalloc + #ifdef _MSC_VER + #define nedblksize _msize + #endif +#endif + +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif + +#if !NO_MALLINFO +struct mallinfo; +#endif + +#if defined(__cplusplus) + #if !defined(NO_NED_NAMESPACE) +namespace nedalloc { + #else +extern "C" { + #endif + #define THROWSPEC throw() +#else + #define THROWSPEC +#endif + +/* These are the global functions */ + +/* Gets the usable size of an allocated block. Note this will always be bigger than what was +asked for due to rounding etc. +*/ +EXTSPEC size_t nedblksize(void *mem) THROWSPEC; + +EXTSPEC void nedsetvalue(void *v) THROWSPEC; + +EXTSPEC MALLOCATTR void * nedmalloc(size_t size) THROWSPEC; +EXTSPEC MALLOCATTR void * nedcalloc(size_t no, size_t size) THROWSPEC; +EXTSPEC MALLOCATTR void * nedrealloc(void *mem, size_t size) THROWSPEC; +EXTSPEC void nedfree(void *mem) THROWSPEC; +EXTSPEC MALLOCATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC; +#if !NO_MALLINFO +EXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC; +#endif +EXTSPEC int nedmallopt(int parno, int value) THROWSPEC; +EXTSPEC int nedmalloc_trim(size_t pad) THROWSPEC; +EXTSPEC void nedmalloc_stats(void) THROWSPEC; +EXTSPEC size_t nedmalloc_footprint(void) THROWSPEC; +EXTSPEC MALLOCATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC; +EXTSPEC MALLOCATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC; + +/* These are the pool functions */ +struct nedpool_t; +typedef struct nedpool_t nedpool; + +/* Creates a memory pool for use with the nedp* functions below. +Capacity is how much to allocate immediately (if you know you'll be allocating a lot +of memory very soon) which you can leave at zero. Threads specifies how many threads +will *normally* be accessing the pool concurrently. Setting this to zero means it +extends on demand, but be careful of this as it can rapidly consume system resources +where bursts of concurrent threads use a pool at once. +*/ +EXTSPEC MALLOCATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC; + +/* Destroys a memory pool previously created by nedcreatepool(). +*/ +EXTSPEC void neddestroypool(nedpool *p) THROWSPEC; + +/* Sets a value to be associated with a pool. You can retrieve this value by passing +any memory block allocated from that pool. +*/ +EXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC; +/* Gets a previously set value using nedpsetvalue() or zero if memory is unknown. +Optionally can also retrieve pool. +*/ +EXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC; + +/* Disables the thread cache for the calling thread, returning any existing cache +data to the central pool. +*/ +EXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC; + +EXTSPEC MALLOCATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC; +EXTSPEC MALLOCATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC; +EXTSPEC MALLOCATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC; +EXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC; +EXTSPEC MALLOCATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC; +#if !NO_MALLINFO +EXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC; +#endif +EXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC; +EXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC; +EXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC; +EXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC; +EXTSPEC MALLOCATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC; +EXTSPEC MALLOCATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC; + +#if defined(__cplusplus) +} +#endif + +#undef MALLOCATTR +#undef EXTSPEC + +#endif From 1afce7945356c2b23caa346ef2e5d9aefb43f458 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Wed, 8 Apr 2009 23:01:47 +0200 Subject: [PATCH 0570/3720] MinGW readdir reimplementation to support d_type The original readdir implementation was fast, but didn't support the d_type. This means that git would do additional lstats for each entry, to figure out if the entry was a directory or not. This unneedingly slowed down many operations, since Windows API provides this information directly when walking the directories. By running this implementation on Moe's repo structure: mkdir bummer && cd bummer; for ((i=0;i<100;i++)); do mkdir $i && pushd $i; for ((j=0;j<1000;j++)); do echo "$j" >$j; done; popd; done We see the following speedups: git add . ------------------- old: 00:00:23(.087) new: 00:00:21(.512) 1.07x git status ------------------- old: 00:00:03(.306) new: 00:00:01(.684) 1.96x git clean -dxf ------------------- old: 00:00:01(.918) new: 00:00:00(.295) 6.50x Signed-off-by: Marius Storm-Olsen --- compat/mingw.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ compat/mingw.h | 29 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 2ab5bbec1f..2951f33d43 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1172,3 +1172,62 @@ char *getpass(const char *prompt) fputs("\n", stderr); return strbuf_detach(&buf, NULL); } + +#ifndef NO_MINGW_REPLACE_READDIR +/* MinGW readdir implementation to avoid extra lstats for Git */ +struct mingw_DIR +{ + struct _finddata_t dd_dta; /* disk transfer area for this dir */ + struct mingw_dirent dd_dir; /* Our own implementation, including d_type */ + long dd_handle; /* _findnext handle */ + int dd_stat; /* 0 = next entry to read is first entry, -1 = off the end, positive = 0 based index of next entry */ + char dd_name[1]; /* given path for dir with search pattern (struct is extended) */ +}; + +struct dirent *mingw_readdir(DIR *dir) +{ + WIN32_FIND_DATAA buf; + HANDLE handle; + struct mingw_DIR *mdir = (struct mingw_DIR*)dir; + + if (!dir->dd_handle) { + errno = EBADF; /* No set_errno for mingw */ + return NULL; + } + + if (dir->dd_handle == (long)INVALID_HANDLE_VALUE && dir->dd_stat == 0) + { + handle = FindFirstFileA(dir->dd_name, &buf); + DWORD lasterr = GetLastError(); + dir->dd_handle = (long)handle; + if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { + errno = err_win_to_posix(lasterr); + return NULL; + } + } else if (dir->dd_handle == (long)INVALID_HANDLE_VALUE) { + return NULL; + } else if (!FindNextFileA((HANDLE)dir->dd_handle, &buf)) { + DWORD lasterr = GetLastError(); + FindClose((HANDLE)dir->dd_handle); + dir->dd_handle = (long)INVALID_HANDLE_VALUE; + /* POSIX says you shouldn't set errno when readdir can't + find any more files; so, if another error we leave it set. */ + if (lasterr != ERROR_NO_MORE_FILES) + errno = err_win_to_posix(lasterr); + return NULL; + } + + /* We get here if `buf' contains valid data. */ + strcpy(dir->dd_dir.d_name, buf.cFileName); + ++dir->dd_stat; + + /* Set file type, based on WIN32_FIND_DATA */ + mdir->dd_dir.d_type = 0; + if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + mdir->dd_dir.d_type |= DT_DIR; + else + mdir->dd_dir.d_type |= DT_REG; + + return (struct dirent*)&dir->dd_dir; +} +#endif // !NO_MINGW_REPLACE_READDIR diff --git a/compat/mingw.h b/compat/mingw.h index b1156b865e..1b91399f40 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -233,3 +233,32 @@ int main(int argc, const char **argv) \ return mingw_main(argc, argv); \ } \ static int mingw_main(c,v) + +#ifndef NO_MINGW_REPLACE_READDIR +/* + * A replacement of readdir, to ensure that it reads the file type at + * the same time. This avoid extra unneeded lstats in git on MinGW + */ +#undef DT_UNKNOWN +#undef DT_DIR +#undef DT_REG +#undef DT_LNK +#define DT_UNKNOWN 0 +#define DT_DIR 1 +#define DT_REG 2 +#define DT_LNK 3 + +struct mingw_dirent +{ + long d_ino; /* Always zero. */ + union { + unsigned short d_reclen; /* Always zero. */ + unsigned char d_type; /* Reimplementation adds this */ + }; + unsigned short d_namlen; /* Length of name in d_name. */ + char d_name[FILENAME_MAX]; /* File name. */ +}; +#define dirent mingw_dirent +#define readdir(x) mingw_readdir(x) +struct dirent *mingw_readdir(DIR *dir); +#endif // !NO_MINGW_REPLACE_READDIR From c893961d488d8e3ecb7dbcfdb3591bc151b4c9bf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 4 May 2009 16:45:46 +0200 Subject: [PATCH 0571/3720] test-chmtime: work around Windows limitation Windows has problems changing the mtime when the file is write protected, even by the owner of said file. Add a Windows-only workaround to change the mode if necessary before trying to change the mtime. Signed-off-by: Johannes Schindelin --- test-chmtime.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test-chmtime.c b/test-chmtime.c index d5358cbaac..fe476cb618 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -87,6 +87,15 @@ int main(int argc, const char *argv[]) return -1; } +#ifdef WIN32 + if (!(sb.st_mode & S_IWUSR) && + chmod(argv[i], sb.st_mode | S_IWUSR)) { + fprintf(stderr, "Could not make user-writable %s: %s", + argv[i], strerror(errno)); + return -1; + } +#endif + utb.actime = sb.st_atime; utb.modtime = set_eq ? set_time : sb.st_mtime + set_time; From 4f372b5e306c8b0745d8fced630d073d2acb4c74 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:30:33 +0200 Subject: [PATCH 0572/3720] Fix warnings in nedmalloc when compiling with GCC 4.4.0 Signed-off-by: Johannes Schindelin --- compat/nedmalloc/malloc.c.h | 4 +++- compat/nedmalloc/nedmalloc.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index 1d9bbe0aba..678beb821a 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -1270,7 +1270,9 @@ int mspace_mallopt(int, int); /*------------------------------ internal #includes ---------------------- */ #ifdef WIN32 +#ifndef __GNUC__ #pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif #endif /* WIN32 */ #include /* for printing in malloc_stats */ @@ -2541,7 +2543,7 @@ struct malloc_params { static struct malloc_params mparams; /* Ensure mparams initialized */ -#define ensure_initialization() (mparams.magic != 0 || init_mparams()) +#define ensure_initialization() if (mparams.magic == 0) init_mparams() #if !ONLY_MSPACES diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index a381a7df36..60a40934af 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -34,7 +34,7 @@ DEALINGS IN THE SOFTWARE. /*#define FULLSANITYCHECKS*/ #include "nedmalloc.h" -#if defined(WIN32) && !defined(__MINGW32__) +#if defined(WIN32) #include #endif #define MSPACES 1 From 5dae887ff1468189d8c900440e30db97d03d8f12 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:31:17 +0200 Subject: [PATCH 0573/3720] MinGW: Fix compiler warning in merge-recursive GCC 4.4.0 on Windows does not like the format %zu. It is quite unlikely, though, that we need more merge bases than a %d can display, so replace the %zu by a %d. Signed-off-by: Johannes Schindelin --- builtin-merge-recursive.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 703045bfc8..d26a96e486 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -45,8 +45,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) bases[bases_count++] = sha; } else - warning("Cannot handle more than %zu bases. " - "Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]); + warning("Cannot handle more than %d bases. " + "Ignoring %s.", + (int)ARRAY_SIZE(bases)-1, argv[i]); } if (argc - i != 3) /* "--" "" "" */ die("Not handling anything other than two heads merge."); From 3c0d7263c5d0fd4c7fd7db50b189a2bc1959ac0f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:45:59 +0200 Subject: [PATCH 0574/3720] MinGW: declare getpass() Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 1b91399f40..4f7ba4c13f 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -38,6 +38,8 @@ struct passwd { char *pw_dir; }; +extern char *getpass(const char *prompt); + struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ From d9215c962be9e94721f6a5565da46891a157f249 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:46:48 +0200 Subject: [PATCH 0575/3720] winansi: fix compile warnings Signed-off-by: Johannes Schindelin --- compat/win32.h | 1 + compat/winansi.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/win32.h b/compat/win32.h index c26384e595..d531130b12 100644 --- a/compat/win32.h +++ b/compat/win32.h @@ -1,5 +1,6 @@ /* common Win32 functions for MinGW and Cygwin */ #include +#include static inline int file_attr_to_st_mode (DWORD attr) { diff --git a/compat/winansi.c b/compat/winansi.c index 4bee335f9e..9217c24b43 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -80,7 +80,7 @@ static void set_console_attr(void) static void erase_in_line(void) { CONSOLE_SCREEN_BUFFER_INFO sbi; - long dummy; /* Needed for Windows 7 (or Vista) regression */ + DWORD dummy; /* Needed for Windows 7 (or Vista) regression */ if (!console) return; From 9b69cf132266161bbb96a705df15808f3ae3e56f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:47:21 +0200 Subject: [PATCH 0576/3720] Shut up GCC 4.4.0 GCC babbles something about "type-punned" pointers. Just add an extra layer of casting to avoid the warning. Signed-off-by: Johannes Schindelin --- decorate.c | 3 ++- object.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/decorate.c b/decorate.c index 82d9e221ea..a216001dd8 100644 --- a/decorate.c +++ b/decorate.c @@ -8,7 +8,8 @@ static unsigned int hash_obj(const struct object *obj, unsigned int n) { - unsigned int hash = *(unsigned int *)obj->sha1; + const void *p = obj->sha1; + unsigned int hash = *(const unsigned int *)p; return hash % n; } diff --git a/object.c b/object.c index 7e6a92c88e..ce294241d3 100644 --- a/object.c +++ b/object.c @@ -45,7 +45,8 @@ int type_from_string(const char *str) static unsigned int hash_obj(struct object *obj, unsigned int n) { - unsigned int hash = *(unsigned int *)obj->sha1; + const void *p = obj->sha1; + unsigned int hash = *(const unsigned int *)p; return hash % n; } From fdffdb2ddbf05442dd2662937e62258991e4b28c Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 18 May 2009 12:42:41 +0100 Subject: [PATCH 0577/3720] git: browsing paths with spaces when using the start command msysGit issue 258 tracks a problem opening a browser onto file paths that contain spaces or parentheses when calling the web--browse script. This path modifies how the start command is called to solve this. Signed-off-by: Pat Thoyts --- git-web--browse.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/git-web--browse.sh b/git-web--browse.sh index 7ed0faddcd..4f5c740df5 100755 --- a/git-web--browse.sh +++ b/git-web--browse.sh @@ -161,9 +161,12 @@ case "$browser" in ;; esac ;; - w3m|links|lynx|open|start) + w3m|links|lynx|open) eval "$browser_path" "$@" ;; + start) + exec "$browser_path" '"web-browse"' "$@" + ;; dillo) "$browser_path" "$@" & ;; From b078c82afda34beb2fa33f7227cc3e10ac3db226 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 18 May 2009 14:53:34 +0200 Subject: [PATCH 0578/3720] Error out rather than hang when plink does not know the host yet As reported in msysGit issue 96, plink wants to interact with the user asking if a host key should be accepted, but this just blocks the terminal, as plink tries to get the answer from stdin. However, stdin is already connected to Git that wants to send input to the remote command. Rather than blocking, just call plink with -batch so that it will error out with an error message. Signed-off-by: Johannes Schindelin --- connect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index b3c4d22050..db7020939a 100644 --- a/connect.c +++ b/connect.c @@ -602,13 +602,15 @@ struct child_process *git_connect(int fd[2], const char *url_orig, die("command line too long"); conn->in = conn->out = -1; - conn->argv = arg = xcalloc(6, sizeof(*arg)); + conn->argv = arg = xcalloc(7, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); int putty = ssh && strstr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; + if (putty) + *arg++ = "-batch"; if (port) { /* P is for PuTTY, p is for OpenSSH */ *arg++ = putty ? "-P" : "-p"; From ac3f43986a2a5948d474adb21cd5fde78178d367 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 May 2009 13:42:04 +0200 Subject: [PATCH 0579/3720] Correctly detect Plink.exe, and avoid passing -batch to TortoisePlink On Windows, file names are case-insensitive, and some versions of TortoisePlink do not handle -batch well (i.e. they do not understand, neither ignore it). Signed-off-by: Johannes Schindelin --- connect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index db7020939a..692d476578 100644 --- a/connect.c +++ b/connect.c @@ -605,11 +605,11 @@ struct child_process *git_connect(int fd[2], const char *url_orig, conn->argv = arg = xcalloc(7, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); - int putty = ssh && strstr(ssh, "plink"); + int putty = ssh && strcasestr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; - if (putty) + if (putty && !strcasestr(ssh, "tortoiseplink")) *arg++ = "-batch"; if (port) { /* P is for PuTTY, p is for OpenSSH */ From 5fb08d69b146757b7bfbfb20c7c002b496e867d4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 23 May 2009 10:49:17 +0200 Subject: [PATCH 0580/3720] MinGW: Teach Makefile to detect msysgit This commit changes handling of the msysgit specific settings, so that they can be applied to Junio's git.git. Some msysgit settings differ from the standard MinGW settings. We move them into a ifndef block that is only evaluated if a file THIS_IS_MSYSGIT is present in the parent directory, which will be the case for an msysgit working environment, and we assume that such a file is not present accidentally. Signed-off-by: Steffen Prohaska --- Makefile | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 52e190be35..e4fa9a4ee2 100644 --- a/Makefile +++ b/Makefile @@ -817,9 +817,6 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) endif ifneq (,$(findstring MINGW,$(uname_S))) pathsep = ; - prefix = - INSTALL = /bin/install - EXTLIBS += /mingw/lib/libz.a NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_SYMLINK_HEAD = YesPlease @@ -838,8 +835,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease - NO_R_TO_GCC_LINKER = YesPlease - INTERNAL_QSORT = YesPlease RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease @@ -853,7 +848,16 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe +ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) htmldir=doc/git/html/ + prefix = + INSTALL = /bin/install + EXTLIBS += /mingw/lib/libz.a + NO_R_TO_GCC_LINKER = YesPlease + INTERNAL_QSORT = YesPlease +else + NO_CURL = YesPlease +endif endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From e564daea9217d848b5869f5e47723890934ae8a7 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 24 May 2009 08:38:21 +0200 Subject: [PATCH 0581/3720] Fix "MinGW: GCC >= 4 does not need SNPRINTF_SIZE_CORR anymore" The commit message of 3a76fdaf98efbb1dc2f71352c811ab6d2710b74f explains that GCC >= 4 does not need SNPRINTF_SIZE_CORR, but the ifdef tested for < 3, instead of < 4. This is fixed. Thanks to Johannes Sixt for spotting the bug. --- compat/snprintf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index 7d780508a7..6c0fb056a5 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -6,7 +6,7 @@ * number of characters to write without the trailing NUL. */ #ifndef SNPRINTF_SIZE_CORR -#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 3 +#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 4 #define SNPRINTF_SIZE_CORR 1 #else #define SNPRINTF_SIZE_CORR 0 From b2bab8d91b346abf4a4603d443df2dce7b62301f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 25 May 2009 06:44:26 +0200 Subject: [PATCH 0582/3720] Revert "Renaming .gitk-new to .gitk fails if there is already a .gitk." This reverts commit 3a8b35c3e37369014dc06c767e8fa569150a1e59 A quick test showed that this is unnecessary. Unfortunately, the commit message does not explain the specific reason for the patch. It could be issues with FAT or Windows shares. We hope that this is fixed since we switched to Tcl/Tk 8.5.5. --- gitk-git/gitk | 1 - 1 file changed, 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index a5f77e2f87..1a7887b252 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2568,7 +2568,6 @@ proc savestuff {w} { } puts $f "}" close $f - catch {file delete "~/.gitk"} file rename -force "~/.gitk-new" "~/.gitk" } set stuffsaved 1 From ef407fda650d652d554e385ec4604c88d39949d4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 25 May 2009 06:56:11 +0200 Subject: [PATCH 0583/3720] Enable THREADED_DELTA_SEARCH only for msysgit, but not mingw in general --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e4fa9a4ee2..1f034e3a91 100644 --- a/Makefile +++ b/Makefile @@ -826,7 +826,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR = YesPlease NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease - THREADED_DELTA_SEARCH = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease @@ -855,8 +854,10 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) EXTLIBS += /mingw/lib/libz.a NO_R_TO_GCC_LINKER = YesPlease INTERNAL_QSORT = YesPlease + THREADED_DELTA_SEARCH = YesPlease else NO_CURL = YesPlease + NO_PTHREADS = YesPlease endif endif ifneq (,$(findstring arm,$(uname_M))) From a464b3e17abc16b3ece8fa8c4b4e98a499873b45 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 1 Jun 2009 08:15:12 +0200 Subject: [PATCH 0584/3720] Move conio.h from win32.h to mingw.c We need conio.h to avoid a warning about the implicit declaration of _getch(). Including it in mingw.c is sufficient. --- compat/mingw.c | 1 + compat/win32.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index d85d68065e..bed417875e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,5 +1,6 @@ #include "../git-compat-util.h" #include "win32.h" +#include #include "../strbuf.h" unsigned int _CRT_fmode = _O_BINARY; diff --git a/compat/win32.h b/compat/win32.h index d531130b12..c26384e595 100644 --- a/compat/win32.h +++ b/compat/win32.h @@ -1,6 +1,5 @@ /* common Win32 functions for MinGW and Cygwin */ #include -#include static inline int file_attr_to_st_mode (DWORD attr) { From 65deb66a2d92ef38d2cdee71328b48a22605ad1b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 17 Jun 2009 14:49:39 +0200 Subject: [PATCH 0585/3720] import-tars: support symlinks Without this patch, symbolic links are turned into empty files. Signed-off-by: Johannes Schindelin --- contrib/fast-import/import-tars.perl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index 6309d146e7..78e40d2a13 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -82,10 +82,16 @@ foreach my $tar_file (@ARGV) $mtime = oct $mtime; next if $typeflag == 5; # directory - print FI "blob\n", "mark :$next_mark\n", "data $size\n"; - while ($size > 0 && read(I, $_, 512) == 512) { - print FI substr($_, 0, $size); - $size -= 512; + print FI "blob\n", "mark :$next_mark\n"; + if ($typeflag == 2) { # symbolic link + print FI "data ", length($linkname), "\n", $linkname; + $mode = 0120000; + } else { + print FI "data $size\n"; + while ($size > 0 && read(I, $_, 512) == 512) { + print FI substr($_, 0, $size); + $size -= 512; + } } print FI "\n"; @@ -118,7 +124,8 @@ EOF { my ($mark, $mode) = @{$files{$path}}; $path =~ s,^([^/]+)/,, if $have_top_dir; - printf FI "M %o :%i %s\n", $mode & 0111 ? 0755 : 0644, $mark, $path; + $mode = $mode & 0111 ? 0755 : 0644 unless $mode == 0120000; + printf FI "M %o :%i %s\n", $mode, $mark, $path; } print FI "\n"; From 7336516a6f2ac781b4a78a73f99e41e9e8b66e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 17 Jun 2009 22:37:31 +0300 Subject: [PATCH 0586/3720] Refactor winsock initialization into a separate function Signed-off-by: Martin Storsjo --- compat/mingw.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index bed417875e..f570d115c9 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -886,16 +886,25 @@ char **env_setenv(char **env, const char *name) return env; } -/* this is the first function to call into WS_32; initialize it */ -#undef gethostbyname -struct hostent *mingw_gethostbyname(const char *host) +static void ensure_socket_initialization(void) { WSADATA wsa; + static int initialized = 0; + + if (initialized) + return; if (WSAStartup(MAKEWORD(2,2), &wsa)) die("unable to initialize winsock subsystem, error %d", WSAGetLastError()); atexit((void(*)(void)) WSACleanup); + initialized = 1; +} + +#undef gethostbyname +struct hostent *mingw_gethostbyname(const char *host) +{ + ensure_socket_initialization(); return gethostbyname(host); } From bc611ebb9212f5a88446e1b9971e30d7e872feeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 18 Jun 2009 09:40:22 +0300 Subject: [PATCH 0587/3720] Enable support for IPv6 on MinGW The IPv6 support functions are loaded dynamically, to maintain backwards compatibility with versions of Windows prior to XP, and fallback wrappers are provided, implemented in terms of gethostbyname and gethostbyaddr. Signed-off-by: Martin Storsjo --- Makefile | 1 - compat/mingw.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++- compat/mingw.h | 13 ++++ 3 files changed, 181 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7a53bb7da1..81d4c8950e 100644 --- a/Makefile +++ b/Makefile @@ -824,7 +824,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_SYMLINK_HEAD = YesPlease - NO_IPV6 = YesPlease NO_SETENV = YesPlease NO_UNSETENV = YesPlease NO_STRCASESTR = YesPlease diff --git a/compat/mingw.c b/compat/mingw.c index f570d115c9..5cda95d084 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -886,10 +886,129 @@ char **env_setenv(char **env, const char *name) return env; } +/* + * Note, this isn't a complete replacement for getaddrinfo. It assumes + * that service contains a numerical port, or that it it is null. It + * does a simple search using gethostbyname, and returns one IPv4 host + * if one was found. + */ +static int WSAAPI getaddrinfo_stub(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + struct hostent *h = gethostbyname(node); + struct addrinfo *ai; + struct sockaddr_in *sin; + + if (!h) + return WSAGetLastError(); + + ai = xmalloc(sizeof(struct addrinfo)); + *res = ai; + ai->ai_flags = 0; + ai->ai_family = AF_INET; + ai->ai_socktype = hints->ai_socktype; + switch (hints->ai_socktype) { + case SOCK_STREAM: + ai->ai_protocol = IPPROTO_TCP; + break; + case SOCK_DGRAM: + ai->ai_protocol = IPPROTO_UDP; + break; + default: + ai->ai_protocol = 0; + break; + } + ai->ai_addrlen = sizeof(struct sockaddr_in); + ai->ai_canonname = strdup(h->h_name); + + sin = xmalloc(ai->ai_addrlen); + memset(sin, 0, ai->ai_addrlen); + sin->sin_family = AF_INET; + if (service) + sin->sin_port = htons(atoi(service)); + sin->sin_addr = *(struct in_addr *)h->h_addr; + ai->ai_addr = (struct sockaddr *)sin; + ai->ai_next = 0; + return 0; +} + +static void WSAAPI freeaddrinfo_stub(struct addrinfo *res) +{ + free(res->ai_canonname); + free(res->ai_addr); + free(res); +} + +static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen, + char *host, DWORD hostlen, + char *serv, DWORD servlen, int flags) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; + if (sa->sa_family != AF_INET) + return EAI_FAMILY; + if (!host && !serv) + return EAI_NONAME; + + if (host && hostlen > 0) { + struct hostent *ent = NULL; + if (!(flags & NI_NUMERICHOST)) + ent = gethostbyaddr((const char *)&sin->sin_addr, + sizeof(sin->sin_addr), AF_INET); + + if (ent) + snprintf(host, hostlen, "%s", ent->h_name); + else if (flags & NI_NAMEREQD) + return EAI_NONAME; + else + snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr)); + } + + if (serv && servlen > 0) { + struct servent *ent = NULL; + if (!(flags & NI_NUMERICSERV)) + ent = getservbyport(sin->sin_port, + flags & NI_DGRAM ? "udp" : "tcp"); + + if (ent) + snprintf(serv, servlen, "%s", ent->s_name); + else + snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); + } + + return 0; +} + +static HMODULE ipv6_dll = NULL; +static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res); +static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res); +static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen, + char *host, DWORD hostlen, + char *serv, DWORD servlen, int flags); +/* + * gai_strerror is an inline function in the ws2tcpip.h header, so we + * don't need to try to load that one dynamically. + */ + +static void socket_cleanup(void) +{ + WSACleanup(); + if (ipv6_dll) + FreeLibrary(ipv6_dll); + ipv6_dll = NULL; + ipv6_freeaddrinfo = freeaddrinfo_stub; + ipv6_getaddrinfo = getaddrinfo_stub; + ipv6_getnameinfo = getnameinfo_stub; +} + static void ensure_socket_initialization(void) { WSADATA wsa; static int initialized = 0; + const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL }; + const char **name; if (initialized) return; @@ -897,7 +1016,35 @@ static void ensure_socket_initialization(void) if (WSAStartup(MAKEWORD(2,2), &wsa)) die("unable to initialize winsock subsystem, error %d", WSAGetLastError()); - atexit((void(*)(void)) WSACleanup); + + for (name = libraries; *name; name++) { + ipv6_dll = LoadLibrary(*name); + if (!ipv6_dll) + continue; + + ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *)) + GetProcAddress(ipv6_dll, "freeaddrinfo"); + ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *, + const struct addrinfo *, + struct addrinfo **)) + GetProcAddress(ipv6_dll, "getaddrinfo"); + ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *, + socklen_t, char *, DWORD, + char *, DWORD, int)) + GetProcAddress(ipv6_dll, "getnameinfo"); + if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) { + FreeLibrary(ipv6_dll); + ipv6_dll = NULL; + } else + break; + } + if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) { + ipv6_freeaddrinfo = freeaddrinfo_stub; + ipv6_getaddrinfo = getaddrinfo_stub; + ipv6_getnameinfo = getnameinfo_stub; + } + + atexit(socket_cleanup); initialized = 1; } @@ -908,6 +1055,26 @@ struct hostent *mingw_gethostbyname(const char *host) return gethostbyname(host); } +void mingw_freeaddrinfo(struct addrinfo *res) +{ + ipv6_freeaddrinfo(res); +} + +int mingw_getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res) +{ + ensure_socket_initialization(); + return ipv6_getaddrinfo(node, service, hints, res); +} + +int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, DWORD hostlen, char *serv, DWORD servlen, + int flags) +{ + ensure_socket_initialization(); + return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); +} + int mingw_socket(int domain, int type, int protocol) { int sockfd; diff --git a/compat/mingw.h b/compat/mingw.h index 4f7ba4c13f..244ace82e1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -1,4 +1,5 @@ #include +#include /* * things that are not available in header files @@ -152,6 +153,18 @@ char *mingw_getenv(const char *name); struct hostent *mingw_gethostbyname(const char *host); #define gethostbyname mingw_gethostbyname +void mingw_freeaddrinfo(struct addrinfo *res); +#define freeaddrinfo mingw_freeaddrinfo + +int mingw_getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res); +#define getaddrinfo mingw_getaddrinfo + +int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, DWORD hostlen, char *serv, DWORD servlen, + int flags); +#define getnameinfo mingw_getnameinfo + int mingw_socket(int domain, int type, int protocol); #define socket mingw_socket From 198cb7c3f0b8420d8ba21fc8005b3ce6091e75b6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 0588/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Signed-off-by: Johannes Schindelin --- http.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index a2720d576d..a7ebbaf94e 100644 --- a/http.c +++ b/http.c @@ -1,5 +1,6 @@ #include "http.h" #include "pack.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -129,6 +130,15 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; + *result = system_path(*result); + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -136,17 +146,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From ed04b5ce213a39f9f0379640d8e4078c0a2635f8 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 0589/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index d508f83349..7a6a82c810 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -898,7 +898,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 069b288d1b44ad729eac9a31193e0b17a6ab5f6b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Jul 2009 22:21:55 +0200 Subject: [PATCH 0590/3720] Skip tests requiring 'iconv' when that is not found Signed-off-by: Johannes Schindelin --- t/t3900-i18n-commit.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 256c4c9701..a0fb178a67 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -64,6 +64,13 @@ test_expect_success 'config to remove customization' ' git config i18n.commitencoding UTF-8 ' +iconv --help 2>/dev/null >/dev/null +test $? = 127 && { + say "No iconv found; skip rest" + test_done + exit +} + test_expect_success 'ISO8859-1 should be shown in UTF-8 now' ' compare_with ISO8859-1 "$TEST_DIRECTORY"/t3900/1-UTF-8.txt ' From ea20f4081910213be44e2f38360099f961091c2c Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Mon, 10 Aug 2009 12:47:37 +0200 Subject: [PATCH 0591/3720] Symlink support Add symlink support; with UAC, you may need administrator's privileges to create symlinks, but you can at least read them. As reparse points on Windows differentiate between file and directory links, we just assume that file links are meant for the time being; it might be very hard to determine the type before the target exists, but it is thinkable to change the type on-the-fly. A bridge to cross when we arrive there (read: something for somebody to fix who actually has that problem). Signed-off-by: Johannes Schindelin --- compat/mingw.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- compat/mingw.h | 6 ++--- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5cda95d084..20f370b73b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,6 +1,7 @@ #include "../git-compat-util.h" #include "win32.h" #include +#include #include "../strbuf.h" unsigned int _CRT_fmode = _O_BINARY; @@ -166,6 +167,21 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_mode = S_IREAD | S_IFLNK; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + } + FindClose(handle); + } + } return 0; } return -1; @@ -1334,6 +1350,58 @@ int link(const char *oldpath, const char *newpath) return 0; } +int symlink(const char *oldpath, const char *newpath) +{ + typedef BOOL WINAPI (*symlink_fn)(const char*, const char*, DWORD); + static symlink_fn create_symbolic_link = NULL; + if (!create_symbolic_link) { + create_symbolic_link = (symlink_fn) GetProcAddress( + GetModuleHandle("kernel32.dll"), "CreateSymbolicLinkA"); + if (!create_symbolic_link) + create_symbolic_link = (symlink_fn)-1; + } + if (create_symbolic_link == (symlink_fn)-1) { + errno = ENOSYS; + return -1; + } + + if (!create_symbolic_link(newpath, oldpath, 0)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + return 0; +} + +int readlink(const char *path, char *buf, size_t bufsiz) +{ + HANDLE handle = CreateFile(path, GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + + if (handle != INVALID_HANDLE_VALUE) { + unsigned char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + DWORD dummy = 0; + if (DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) { + REPARSE_DATA_BUFFER *b = (REPARSE_DATA_BUFFER *) buffer; + if (b->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + int len = b->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + int offset = b->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + snprintf(buf, bufsiz, "%*ls", len, & b->SymbolicLinkReparseBuffer.PathBuffer[offset]); + CloseHandle(handle); + return len; + } + } + + CloseHandle(handle); + } + + errno = EINVAL; + return -1; +} + char *getpass(const char *prompt) { struct strbuf buf = STRBUF_INIT; @@ -1399,7 +1467,10 @@ struct dirent *mingw_readdir(DIR *dir) /* Set file type, based on WIN32_FIND_DATA */ mdir->dd_dir.d_type = 0; - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + if ((buf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (buf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) + mdir->dd_dir.d_type |= DT_LNK; + else if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) mdir->dd_dir.d_type |= DT_DIR; else mdir->dd_dir.d_type |= DT_REG; diff --git a/compat/mingw.h b/compat/mingw.h index c76af61617..4f9f7f4887 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -66,10 +66,6 @@ struct itimerval { * trivial stubs */ -static inline int readlink(const char *path, char *buf, size_t bufsiz) -{ errno = ENOSYS; return -1; } -static inline int symlink(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) @@ -138,6 +134,8 @@ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); +int symlink(const char *oldpath, const char *newpath); +int readlink(const char *path, char *buf, size_t bufsiz); /* * replacements of existing functions From afb9111bacf3da37d87186057739b3e3fbf044b0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 18:08:44 +0200 Subject: [PATCH 0592/3720] Fix style of multi-line comments In git.git, we want multi-line comments between single /* and */ in a line. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 20f370b73b..ed2664dc00 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -147,7 +147,8 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } -/* We keep the do_lstat code in a separate function to avoid recursion. +/* + * We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. */ @@ -187,7 +188,8 @@ static int do_lstat(const char *file_name, struct stat *buf) return -1; } -/* We provide our own lstat/fstat functions, since the provided +/* + * We provide our own lstat/fstat functions, since the provided * lstat/fstat functions are so slow. These stat functions are * tailored for Git's usage (read: fast), and are not meant to be * complete. Note that Git stat()s are redirected to mingw_lstat() @@ -201,7 +203,8 @@ int mingw_lstat(const char *file_name, struct stat *buf) if (!do_lstat(file_name, buf)) return 0; - /* if file_name ended in a '/', Windows returned ENOENT; + /* + * if file_name ended in a '/', Windows returned ENOENT; * try again without trailing slashes */ if (errno != ENOENT) @@ -368,7 +371,8 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout) return errno = EINVAL, error("poll timeout not supported"); } - /* When there is only one fd to wait for, then we pretend that + /* + * When there is only one fd to wait for, then we pretend that * input is available and let the actual wait happen when the * caller invokes read(). */ @@ -408,7 +412,8 @@ repeat: ufds[i].revents = 0; } if (!pending) { - /* The only times that we spin here is when the process + /* + * The only times that we spin here is when the process * that is connected through the pipes is waiting for * its own input data to become available. But since * the process (pack-objects) is itself CPU intensive, @@ -663,7 +668,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (cons == INVALID_HANDLE_VALUE) { - /* There is no console associated with this process. + /* + * There is no console associated with this process. * Since the child is a console process, Windows * would normally create a console window. But * since we'll be redirecting std streams, we do @@ -674,7 +680,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, */ flags = DETACHED_PROCESS; } else { - /* There is already a console. If we specified + /* + * There is already a console. If we specified * DETACHED_PROCESS here, too, Windows would * disassociate the child from the console. * The same is true for CREATE_NO_WINDOW. @@ -874,9 +881,7 @@ static int lookup_env(char **env, const char *name, size_t nmln) return -1; } -/* - * If name contains '=', then sets the variable, otherwise it unsets it - */ +/* If name contains '=', then sets the variable, otherwise it unsets it */ char **env_setenv(char **env, const char *name) { char *eq = strchrnul(name, '='); @@ -1195,7 +1200,8 @@ static int timer_interval; static int one_shot; static sig_handler_t timer_fn = SIG_DFL; -/* The timer works like this: +/* + * The timer works like this: * The thread, ticktack(), is a trivial routine that most of the time * only waits to receive the signal to terminate. The main thread tells * the thread to terminate by setting the timer_event to the signalled @@ -1454,8 +1460,10 @@ struct dirent *mingw_readdir(DIR *dir) DWORD lasterr = GetLastError(); FindClose((HANDLE)dir->dd_handle); dir->dd_handle = (long)INVALID_HANDLE_VALUE; - /* POSIX says you shouldn't set errno when readdir can't - find any more files; so, if another error we leave it set. */ + /* + * POSIX says you shouldn't set errno when readdir can't + * find any more files; so, if another error we leave it set. + */ if (lasterr != ERROR_NO_MORE_FILES) errno = err_win_to_posix(lasterr); return NULL; From 8653dacef71c86e5a95d32eda5240bbafc40d1a6 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Sat, 8 Aug 2009 22:44:01 +0200 Subject: [PATCH 0593/3720] On Windows, mark directory hidden when starting with dot. In Windows a file or directory starting with a dot is not automatically hidden. So lets mark it as hidden when such a directory is created. This fixes msysGit issue 288. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- compat/mingw.c | 26 ++++++++++++++++++++++++++ compat/mingw.h | 9 +++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5cda95d084..c3f5cef22c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -118,6 +118,32 @@ static int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index c76af61617..19a0205f86 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -100,12 +100,6 @@ static inline int fcntl(int fd, int cmd, long arg) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} -#define mkdir mingw_mkdir - static inline int mingw_unlink(const char *pathname) { /* read-only files cannot be removed */ @@ -143,6 +137,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_mkdir(const char *path, int mode); +#define mkdir mingw_mkdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 996ff4a9ae8d4db3b5fedea3f1cf03ea0f689035 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Sat, 8 Aug 2009 22:59:27 +0200 Subject: [PATCH 0594/3720] Make auto-hiding dot-files optional on Windows. Although a file starting with a dot usually ought to be hidden, there could be reasons users do not want it to happen automatically. Original patch by Erik Faye-Lund. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- cache.h | 1 + compat/mingw.c | 3 ++- config.c | 5 +++++ environment.c | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cache.h b/cache.h index e6c7f3307d..f591437a50 100644 --- a/cache.h +++ b/cache.h @@ -518,6 +518,7 @@ extern size_t delta_base_cache_limit; extern int auto_crlf; extern int fsync_object_files; extern int core_preload_index; +extern int hide_dotfiles; enum safe_crlf { SAFE_CRLF_FALSE = 0, diff --git a/compat/mingw.c b/compat/mingw.c index c3f5cef22c..665d861389 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -130,8 +130,9 @@ static int make_hidden(const char *path) #undef mkdir int mingw_mkdir(const char *path, int mode) { + extern int hide_dotfiles; int ret = mkdir(path); - if (!ret) { + if (!ret && hide_dotfiles) { /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when diff --git a/config.c b/config.c index 738b24419d..fc45ea2198 100644 --- a/config.c +++ b/config.c @@ -505,6 +505,11 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 8f5eaa7dd8..940f3cfa3a 100644 --- a/environment.c +++ b/environment.c @@ -48,6 +48,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_replace_parents = 1; +int hide_dotfiles = 1; /* Parallel index stat data preload? */ int core_preload_index = 0; From 5d098f4e5f1e21d802769f16058118ec12cdda25 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 9 Aug 2009 19:08:05 +0200 Subject: [PATCH 0595/3720] Document the core.hideDotFiles variable Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- Documentation/config.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index c6f09f801a..7c6f7fcb87 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -118,6 +118,10 @@ core.fileMode:: the working copy are ignored; useful on broken filesystems like FAT. See linkgit:git-update-index[1]. True by default. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories whose name starts with a dot as hidden. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful From 2328ceef54b7b2e40ad66ecd74a3451bf7c3c6d5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 9 Aug 2009 19:12:17 +0200 Subject: [PATCH 0596/3720] Windows: mark newly-created files whose name starts with a dot as hidden Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- Documentation/config.txt | 2 +- compat/mingw.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7c6f7fcb87..30ab22b840 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -120,7 +120,7 @@ core.fileMode:: core.hideDotFiles:: (Windows-only) If true (which is the default), mark newly-created - directories whose name starts with a dot as hidden. + directories and files whose name starts with a dot as hidden. core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, diff --git a/compat/mingw.c b/compat/mingw.c index 665d861389..a68ef11696 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" +extern int hide_dotfiles; unsigned int _CRT_fmode = _O_BINARY; static int err_win_to_posix(DWORD winerr) @@ -130,7 +131,6 @@ static int make_hidden(const char *path) #undef mkdir int mingw_mkdir(const char *path, int mode) { - extern int hide_dotfiles; int ret = mkdir(path); if (!ret && hide_dotfiles) { /* @@ -162,6 +162,16 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && hide_dotfiles) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } From 4863902f4f89d00a7fa916d11cf24fe1cb9b8160 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Wed, 12 Aug 2009 23:40:50 +0200 Subject: [PATCH 0597/3720] Windows: mark newly-created dot files by fopen() as hidden Files starting with a dot are considered "hidden", i.e. you have to ask explicitely to see them. On Windows, this is not done automatically, as Windows has its own mechanism. We already mark dot directories created by mkdir() and dot files created by open() as hidden, so let's do that with fopen(), too (but only if the file was just created, not when it already exists). Naturally, we make this behavior optional on core.hideDotFiles. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index a68ef11696..293bd5999d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,6 +175,24 @@ int mingw_open (const char *filename, int oflags, ...) return fd; } +#undef fopen +FILE *mingw_fopen (const char *filename, const char *mode) +{ + int hide = 0; + if (hide_dotfiles && basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); + + FILE *file = fopen(filename, mode); + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; +} + static inline time_t filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; diff --git a/compat/mingw.h b/compat/mingw.h index 19a0205f86..8fe1773974 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -143,6 +143,9 @@ int mingw_mkdir(const char *path, int mode); int mingw_open (const char *filename, int oflags, ...); #define open mingw_open +FILE *mingw_fopen (const char *filename, const char *mode); +#define fopen mingw_fopen + char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd From 3c150abb1016cef67dfa2644578dbca8700e280c Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 16 Aug 2009 13:34:03 +0800 Subject: [PATCH 0598/3720] Avoid declaration after instruction Microsoft Visual C++ does not understand this C99 style. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/mingw.c | 16 ++++++++++++---- help.c | 3 ++- run-command.c | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 62983d0e32..d262e1c226 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -151,13 +151,17 @@ int mingw_open (const char *filename, int oflags, ...) { va_list args; unsigned mode; + int fd; + va_start(args, oflags); mode = va_arg(args, int); va_end(args); if (!strcmp(filename, "/dev/null")) filename = "nul"; - int fd = open(filename, oflags, mode); + + fd = open(filename, oflags, mode); + if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { DWORD attrs = GetFileAttributes(filename); if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) @@ -656,10 +660,11 @@ static char **get_path_split(void) static void free_path_split(char **path) { + char **p = path; + if (!path) return; - char **p = path; while (*p) free(*p++); free(path); @@ -1361,9 +1366,11 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out) #undef signal sig_handler_t mingw_signal(int sig, sig_handler_t handler) { + sig_handler_t old; + if (sig != SIGALRM) return signal(sig, handler); - sig_handler_t old = timer_fn; + old = timer_fn; timer_fn = handler; return old; } @@ -1502,8 +1509,9 @@ struct dirent *mingw_readdir(DIR *dir) if (dir->dd_handle == (long)INVALID_HANDLE_VALUE && dir->dd_stat == 0) { + DWORD lasterr; handle = FindFirstFileA(dir->dd_name, &buf); - DWORD lasterr = GetLastError(); + lasterr = GetLastError(); dir->dd_handle = (long)handle; if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { errno = err_win_to_posix(lasterr); diff --git a/help.c b/help.c index 6c46d8b494..399b0b40f4 100644 --- a/help.c +++ b/help.c @@ -127,7 +127,7 @@ static int is_executable(const char *name) return 0; #ifdef __MINGW32__ - /* cannot trust the executable bit, peek into the file instead */ +{ /* cannot trust the executable bit, peek into the file instead */ char buf[3] = { 0 }; int n; int fd = open(name, O_RDONLY); @@ -140,6 +140,7 @@ static int is_executable(const char *name) st.st_mode |= S_IXUSR; close(fd); } +} #endif return st.st_mode & S_IXUSR; } diff --git a/run-command.c b/run-command.c index ff3d8e2d8b..d1df7abe9a 100644 --- a/run-command.c +++ b/run-command.c @@ -123,6 +123,7 @@ int start_command(struct child_process *cmd) exit(127); } #else +{ int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ const char **sargv = cmd->argv; char **env = environ; @@ -186,6 +187,7 @@ int start_command(struct child_process *cmd) dup2(s1, 1), close(s1); if (s2 >= 0) dup2(s2, 2), close(s2); +} #endif if (cmd->pid < 0) { From 0b79d7e97888f2f26820ac7c7d5b911e4f84821e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 10:30:55 +0200 Subject: [PATCH 0599/3720] Fix a few old-style function declarations in compat/ Signed-off-by: Johannes Schindelin --- compat/fnmatch/fnmatch.c | 20 +-- compat/mingw.c | 2 +- compat/mingw.h | 2 +- compat/nedmalloc/malloc.c.h | 2 +- compat/nedmalloc/nedmalloc.c | 4 +- compat/regex/regex.c | 240 +++++++++++------------------------ 6 files changed, 84 insertions(+), 186 deletions(-) diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 14feac7fe1..1180fc793f 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -130,10 +130,7 @@ extern int errno; /* This function doesn't exist on most systems. */ # if !defined HAVE___STRCHRNUL && !defined _LIBC -static char * -__strchrnul (s, c) - const char *s; - int c; +static char * __strchrnul (const char *s, int c) { char *result = strchr (s, c); if (result == NULL) @@ -153,13 +150,8 @@ __strchrnul (s, c) static int internal_fnmatch __P ((const char *pattern, const char *string, int no_leading_period, int flags)) internal_function; -static int -internal_function -internal_fnmatch (pattern, string, no_leading_period, flags) - const char *pattern; - const char *string; - int no_leading_period; - int flags; +static int internal_function internal_fnmatch (const char *pattern, + const char *string, int no_leading_period, int flags) { register const char *p = pattern, *n = string; register unsigned char c; @@ -476,11 +468,7 @@ internal_fnmatch (pattern, string, no_leading_period, flags) } -int -fnmatch (pattern, string, flags) - const char *pattern; - const char *string; - int flags; +int fnmatch (const char *pattern, const char *string, int flags) { return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); } diff --git a/compat/mingw.c b/compat/mingw.c index d262e1c226..d70fd21573 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -907,7 +907,7 @@ void mingw_execvp(const char *cmd, char *const *argv) free_path_split(path); } -char **copy_environ() +char **copy_environ(void) { char **env; int i = 0; diff --git a/compat/mingw.h b/compat/mingw.h index 201e79c741..cfbcc0e0cd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -78,7 +78,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline int getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index 74c42e3162..41b8698ab3 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -1802,7 +1802,7 @@ struct win32_mlock_t static MLOCK_T malloc_global_mutex = { 0, 0, 0}; -static FORCEINLINE long win32_getcurrentthreadid() { +static FORCEINLINE long win32_getcurrentthreadid(void) { #ifdef _MSC_VER #if defined(_M_IX86) long *threadstruct=(long *)__readfsdword(0x18); diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index d9a17a8057..229f942d10 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -159,8 +159,8 @@ struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); } #endif int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); } int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); } -void nedmalloc_stats() THROWSPEC { nedpmalloc_stats(0); } -size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint(0); } +void nedmalloc_stats(void) THROWSPEC { nedpmalloc_stats(0); } +size_t nedmalloc_footprint(void) THROWSPEC { return nedpmalloc_footprint(0); } void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); } void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); } diff --git a/compat/regex/regex.c b/compat/regex/regex.c index 5ea007567d..9e8a203857 100644 --- a/compat/regex/regex.c +++ b/compat/regex/regex.c @@ -64,8 +64,7 @@ extern char *re_syntax_table; static char re_syntax_table[CHAR_SET_SIZE]; -static void -init_syntax_once () +static void init_syntax_once(void) { register int c; static int done = 0; @@ -380,10 +379,7 @@ typedef enum } while (0) #ifdef DEBUG -static void -extract_number (dest, source) - int *dest; - unsigned char *source; +static void extract_number(int *dest, unsigned char *source) { int temp = SIGN_EXTEND_CHAR (*(source + 1)); *dest = *source & 0377; @@ -407,10 +403,8 @@ extract_number (dest, source) } while (0) #ifdef DEBUG -static void -extract_number_and_incr (destination, source) - int *destination; - unsigned char **source; +static void extract_number_and_incr(int *destination, + unsigned char **source) { extract_number (destination, *source); *source += 2; @@ -455,9 +449,7 @@ extern void printchar (); /* Print the fastmap in human-readable form. */ -void -print_fastmap (fastmap) - char *fastmap; +void print_fastmap(char *fastmap) { unsigned was_a_range = 0; unsigned i = 0; @@ -487,10 +479,8 @@ print_fastmap (fastmap) /* Print a compiled pattern string in human-readable form, starting at the START pointer into it and ending just before the pointer END. */ -void -print_partial_compiled_pattern (start, end) - unsigned char *start; - unsigned char *end; +void print_partial_compiled_pattern(unsigned char *start, + unsigned char *end) { int mcnt, mcnt2; unsigned char *p = start; @@ -695,9 +685,7 @@ print_partial_compiled_pattern (start, end) } -void -print_compiled_pattern (bufp) - struct re_pattern_buffer *bufp; +void print_compiled_pattern(struct re_pattern_buffer *bufp) { unsigned char *buffer = bufp->buffer; @@ -722,13 +710,9 @@ print_compiled_pattern (bufp) } -void -print_double_string (where, string1, size1, string2, size2) - const char *where; - const char *string1; - const char *string2; - int size1; - int size2; +void print_double_string(const char *where, + const char *string1, int size1, + const char *string2, int size2) { unsigned this_char; @@ -777,9 +761,7 @@ reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; The argument SYNTAX is a bit mask comprised of the various bits defined in regex.h. We return the old syntax. */ -reg_syntax_t -re_set_syntax (syntax) - reg_syntax_t syntax; +reg_syntax_t re_set_syntax(reg_syntax_t syntax) { reg_syntax_t ret = re_syntax_options; @@ -1031,12 +1013,9 @@ typedef struct The `fastmap' and `newline_anchor' fields are neither examined nor set. */ -static reg_errcode_t -regex_compile (pattern, size, syntax, bufp) - const char *pattern; - int size; - reg_syntax_t syntax; - struct re_pattern_buffer *bufp; +static reg_errcode_t regex_compile(const char *pattern, + int size, reg_syntax_t syntax, + struct re_pattern_buffer *bufp) { /* We fetch characters from PATTERN here. Even though PATTERN is `char *' (i.e., signed), we declare these variables as unsigned, so @@ -2036,11 +2015,8 @@ regex_compile (pattern, size, syntax, bufp) /* Store OP at LOC followed by two-byte integer parameter ARG. */ -static void -store_op1 (op, loc, arg) - re_opcode_t op; - unsigned char *loc; - int arg; +static void store_op1(re_opcode_t op, unsigned char *loc, + int arg) { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg); @@ -2049,11 +2025,8 @@ store_op1 (op, loc, arg) /* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ -static void -store_op2 (op, loc, arg1, arg2) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; +static void store_op2(re_opcode_t op, unsigned char *loc, + int arg1, int arg2) { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg1); @@ -2064,12 +2037,8 @@ store_op2 (op, loc, arg1, arg2) /* Copy the bytes from LOC to END to open up three bytes of space at LOC for OP followed by two-byte integer parameter ARG. */ -static void -insert_op1 (op, loc, arg, end) - re_opcode_t op; - unsigned char *loc; - int arg; - unsigned char *end; +static void insert_op1(re_opcode_t op, unsigned char *loc, + int arg, unsigned char *end) { register unsigned char *pfrom = end; register unsigned char *pto = end + 3; @@ -2083,12 +2052,8 @@ insert_op1 (op, loc, arg, end) /* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ -static void -insert_op2 (op, loc, arg1, arg2, end) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; - unsigned char *end; +static void insert_op2(re_opcode_t op, unsigned char *loc, + int arg1, int arg2, unsigned char *end) { register unsigned char *pfrom = end; register unsigned char *pto = end + 5; @@ -2104,10 +2069,8 @@ insert_op2 (op, loc, arg1, arg2, end) after an alternative or a begin-subexpression. We assume there is at least one character before the ^. */ -static boolean -at_begline_loc_p (pattern, p, syntax) - const char *pattern, *p; - reg_syntax_t syntax; +static boolean at_begline_loc_p(const char *pattern, + const char *p, reg_syntax_t syntax) { const char *prev = p - 2; boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; @@ -2123,10 +2086,8 @@ at_begline_loc_p (pattern, p, syntax) /* The dual of at_begline_loc_p. This one is for $. We assume there is at least one character after the $, i.e., `P < PEND'. */ -static boolean -at_endline_loc_p (p, pend, syntax) - const char *p, *pend; - int syntax; +static boolean at_endline_loc_p(const char *p, + const char *pend, int syntax) { const char *next = p; boolean next_backslash = *next == '\\'; @@ -2145,10 +2106,8 @@ at_endline_loc_p (p, pend, syntax) /* Returns true if REGNUM is in one of COMPILE_STACK's elements and false if it's not. */ -static boolean -group_in_compile_stack (compile_stack, regnum) - compile_stack_type compile_stack; - regnum_t regnum; +static boolean group_in_compile_stack(compile_stack_type + compile_stack, regnum_t regnum) { int this_element; @@ -2173,12 +2132,9 @@ group_in_compile_stack (compile_stack, regnum) We use these short variable names so we can use the same macros as `regex_compile' itself. */ -static reg_errcode_t -compile_range (p_ptr, pend, translate, syntax, b) - const char **p_ptr, *pend; - char *translate; - reg_syntax_t syntax; - unsigned char *b; +static reg_errcode_t compile_range(const char **p_ptr, + const char *pend, char *translate, + reg_syntax_t syntax, unsigned char *b) { unsigned this_char; @@ -2505,9 +2461,7 @@ typedef struct Returns 0 if we succeed, -2 if an internal error. */ -int -re_compile_fastmap (bufp) - struct re_pattern_buffer *bufp; +int re_compile_fastmap(struct re_pattern_buffer *bufp) { int j, k; fail_stack_type fail_stack; @@ -2790,12 +2744,10 @@ re_compile_fastmap (bufp) PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ -void -re_set_registers (bufp, regs, num_regs, starts, ends) - struct re_pattern_buffer *bufp; - struct re_registers *regs; - unsigned num_regs; - regoff_t *starts, *ends; +void re_set_registers(struct re_pattern_buffer *bufp, + struct re_registers *regs, + unsigned num_regs, + regoff_t *starts, regoff_t *ends) { if (num_regs) { @@ -2817,12 +2769,10 @@ re_set_registers (bufp, regs, num_regs, starts, ends) /* Like re_search_2, below, but only one string is specified, and doesn't let you say where to stop matching. */ -int -re_search (bufp, string, size, startpos, range, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, startpos, range; - struct re_registers *regs; +int re_search(struct re_pattern_buffer *bufp, + const char *string, int size, + int startpos, int range, + struct re_registers *regs) { return re_search_2 (bufp, NULL, 0, string, size, startpos, range, regs, size); @@ -2850,15 +2800,11 @@ re_search (bufp, string, size, startpos, range, regs) found, -1 if no match, or -2 if error (such as failure stack overflow). */ -int -re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int startpos; - int range; - struct re_registers *regs; - int stop; +int re_search_2(struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int startpos, int range, + struct re_registers *regs, int stop) { int val; register char *fastmap = bufp->fastmap; @@ -3109,12 +3055,9 @@ typedef union #ifndef emacs /* Emacs never uses this. */ /* re_match is like re_match_2 except it takes only a single string. */ -int -re_match (bufp, string, size, pos, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, pos; - struct re_registers *regs; +int re_match(struct re_pattern_buffer *bufp, + const char *string, int size, int pos, + struct re_registers *regs) { return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); } @@ -3134,14 +3077,10 @@ re_match (bufp, string, size, pos, regs) failure stack overflowing). Otherwise, we return the length of the matched substring. */ -int -re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int pos; - struct re_registers *regs; - int stop; +int re_match_2(struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, struct re_registers *regs, int stop) { /* General temporaries. */ int mcnt; @@ -4330,10 +4269,9 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) We don't handle duplicates properly (yet). */ -static boolean -group_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; +static boolean group_match_null_string_p(unsigned char **p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; /* Point to after the args to the start_memory. */ @@ -4439,10 +4377,9 @@ group_match_null_string_p (p, end, reg_info) It expects P to be the first byte of a single alternative and END one byte past the last. The alternative can contain groups. */ -static boolean -alt_match_null_string_p (p, end, reg_info) - unsigned char *p, *end; - register_info_type *reg_info; +static boolean alt_match_null_string_p(unsigned char *p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; unsigned char *p1 = p; @@ -4476,10 +4413,9 @@ alt_match_null_string_p (p, end, reg_info) Sets P to one after the op and its arguments, if any. */ -static boolean -common_op_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; +static boolean common_op_match_null_string_p(unsigned char **p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; boolean ret; @@ -4564,13 +4500,8 @@ common_op_match_null_string_p (p, end, reg_info) /* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN bytes; nonzero otherwise. */ -static int -bcmp_translate( - unsigned char *s1, - unsigned char *s2, - int len, - char *translate -) +static int bcmp_translate(unsigned char *s1, unsigned char *s2, + int len, char *translate) { register unsigned char *p1 = s1, *p2 = s2; while (len) @@ -4592,11 +4523,8 @@ bcmp_translate( We call regex_compile to do the actual compilation. */ -const char * -re_compile_pattern (pattern, length, bufp) - const char *pattern; - int length; - struct re_pattern_buffer *bufp; +const char *re_compile_pattern(const char *pattern, + int length, struct re_pattern_buffer *bufp) { reg_errcode_t ret; @@ -4625,9 +4553,7 @@ re_compile_pattern (pattern, length, bufp) /* BSD has one and only one pattern buffer. */ static struct re_pattern_buffer re_comp_buf; -char * -re_comp (s) - const char *s; +char *re_comp(const char *s) { reg_errcode_t ret; @@ -4663,9 +4589,7 @@ re_comp (s) } -int -re_exec (s) - const char *s; +int re_exec(const char *s) { const int len = strlen (s); return @@ -4711,11 +4635,7 @@ re_exec (s) It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for the return codes and their meanings.) */ -int -regcomp (preg, pattern, cflags) - regex_t *preg; - const char *pattern; - int cflags; +int regcomp(regex_t *preg, const char *pattern, int cflags) { reg_errcode_t ret; unsigned syntax @@ -4786,13 +4706,9 @@ regcomp (preg, pattern, cflags) We return 0 if we find a match and REG_NOMATCH if not. */ -int -regexec (preg, string, nmatch, pmatch, eflags) - const regex_t *preg; - const char *string; - size_t nmatch; - regmatch_t pmatch[]; - int eflags; +int regexec(const regex_t *preg, const char *string, + size_t nmatch, regmatch_t pmatch[], + int eflags) { int ret; struct re_registers regs; @@ -4851,12 +4767,8 @@ regexec (preg, string, nmatch, pmatch, eflags) /* Returns a message corresponding to an error code, ERRCODE, returned from either regcomp or regexec. We don't use PREG here. */ -size_t -regerror (errcode, preg, errbuf, errbuf_size) - int errcode; - const regex_t *preg; - char *errbuf; - size_t errbuf_size; +size_t regerror(int errcode, const regex_t *preg, + char *errbuf, size_t errbuf_size) { const char *msg; size_t msg_size; @@ -4895,9 +4807,7 @@ regerror (errcode, preg, errbuf, errbuf_size) /* Free dynamically allocated space used by PREG. */ -void -regfree (preg) - regex_t *preg; +void regfree(regex_t *preg) { if (preg->buffer != NULL) free (preg->buffer); From 95971f14a81d531b8fcb34e66b82c7fe537003dc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 10:31:29 +0200 Subject: [PATCH 0600/3720] compat/mingw.c: Fix declaration after instruction Signed-off-by: Johannes Schindelin --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index d70fd21573..449bea140a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -184,10 +184,11 @@ int mingw_open (const char *filename, int oflags, ...) FILE *mingw_fopen (const char *filename, const char *mode) { int hide = 0; + FILE *file; if (hide_dotfiles && basename((char*)filename)[0] == '.') hide = access(filename, F_OK); - FILE *file = fopen(filename, mode); + file = fopen(filename, mode); /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when From 1edac2172dd74fa656dc6e4a9e450751f9a5d1a9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 09:59:58 +0200 Subject: [PATCH 0601/3720] MinGW means that we have gcc, so we can add gcc-specific compiler options These were suggested by Junio at some stage. Signed-off-by: Johannes Schindelin --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 690ac55b7d..e0f9a631c2 100644 --- a/Makefile +++ b/Makefile @@ -905,6 +905,9 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_REGEX = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" + # We have GCC, so let's make use of those nice options + COMPAT_CFLAGS += -Werror -Wno-pointer-to-int-cast \ + -Wold-style-definition -Wdeclaration-after-statement COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe From 8d7c8c95b6d995555d514b43ab6969a1cf7e3044 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 16 Aug 2009 13:53:30 +0800 Subject: [PATCH 0602/3720] Define SNPRINTF_SIZE_CORR=1 for Microsoft Visual C++ The Microsoft C runtime's vsnprintf function does not add NUL at the end of the buffer. Further, Microsoft deprecated vsnprintf in favor of _vsnprintf, so add a #define to that end. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/snprintf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index 6c0fb056a5..47b2b8a55e 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -6,7 +6,7 @@ * number of characters to write without the trailing NUL. */ #ifndef SNPRINTF_SIZE_CORR -#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 4 +#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 4 || defined(_MSC_VER) #define SNPRINTF_SIZE_CORR 1 #else #define SNPRINTF_SIZE_CORR 0 @@ -14,6 +14,11 @@ #endif #undef vsnprintf + +#if defined(_MSC_VER) +#define vsnprintf _vsnprintf +#endif + int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { char *s; From d84f77b0cc2381c59d39011d92bd0ad6740f96ab Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 18 Aug 2009 23:39:54 +0800 Subject: [PATCH 0603/3720] Test for WIN32 instead of __MINGW32_ The code which is conditional on MinGW32 is actually conditional on Windows. Use the WIN32 symbol, which is defined by the MINGW32 and MSVC environments, but not by Cygwin. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- help.c | 2 +- run-command.c | 8 ++++---- run-command.h | 2 +- setup.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/help.c b/help.c index 399b0b40f4..9dae4e7551 100644 --- a/help.c +++ b/help.c @@ -126,7 +126,7 @@ static int is_executable(const char *name) !S_ISREG(st.st_mode)) return 0; -#ifdef __MINGW32__ +#ifdef WIN32 { /* cannot trust the executable bit, peek into the file instead */ char buf[3] = { 0 }; int n; diff --git a/run-command.c b/run-command.c index d1df7abe9a..d0833f846e 100644 --- a/run-command.c +++ b/run-command.c @@ -67,7 +67,7 @@ int start_command(struct child_process *cmd) trace_argv_printf(cmd->argv, "trace: run_command:"); -#ifndef __MINGW32__ +#ifndef WIN32 fflush(NULL); cmd->pid = fork(); if (!cmd->pid) { @@ -294,7 +294,7 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const return run_command(&cmd); } -#ifdef __MINGW32__ +#ifdef WIN32 static __stdcall unsigned run_thread(void *data) { struct async *async = data; @@ -310,7 +310,7 @@ int start_async(struct async *async) return error("cannot create pipe: %s", strerror(errno)); async->out = pipe_out[0]; -#ifndef __MINGW32__ +#ifndef WIN32 /* Flush stdio before fork() to avoid cloning buffers */ fflush(NULL); @@ -339,7 +339,7 @@ int start_async(struct async *async) int finish_async(struct async *async) { -#ifndef __MINGW32__ +#ifndef WIN32 int ret = 0; if (wait_or_whine(async->pid)) diff --git a/run-command.h b/run-command.h index e345502843..09a4cb25b2 100644 --- a/run-command.h +++ b/run-command.h @@ -79,7 +79,7 @@ struct async { int (*proc)(int fd, void *data); void *data; int out; /* caller reads from here and closes it */ -#ifndef __MINGW32__ +#ifndef WIN32 pid_t pid; #else HANDLE tid; diff --git a/setup.c b/setup.c index e3781b656d..029371e584 100644 --- a/setup.c +++ b/setup.c @@ -41,7 +41,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; -#ifndef __MINGW32__ +#ifndef WIN32 if (!pfx || !*pfx || is_absolute_path(arg)) return arg; memcpy(path, pfx, pfx_len); From e76177f62a158b71c22cc3f7fa3aaa0ffa646860 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 17 Aug 2009 14:52:01 +0800 Subject: [PATCH 0604/3720] mingw.c: Use the O_BINARY flag to open files On Windows, non-text files must be opened using the O_BINARY flag. MinGW does this for us automatically, but Microsoft Visual C++ does not. So let's be explicit. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 449bea140a..5d3d24617e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -160,7 +160,7 @@ int mingw_open (const char *filename, int oflags, ...) if (!strcmp(filename, "/dev/null")) filename = "nul"; - fd = open(filename, oflags, mode); + fd = open(filename, oflags | O_BINARY, mode); if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { DWORD attrs = GetFileAttributes(filename); @@ -353,7 +353,7 @@ int mkstemp(char *template) char *filename = mktemp(template); if (filename == NULL) return -1; - return open(filename, O_RDWR | O_CREAT, 0600); + return open(filename, O_RDWR | O_CREAT | O_BINARY, 0600); } int gettimeofday(struct timeval *tv, void *tz) From d92d40ecd04798b7a31b9a5f38052d43c86e2ae0 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 18 Aug 2009 23:59:53 +0800 Subject: [PATCH 0605/3720] Place __stdcall between return value and function name MSVC requires that __stdcall be between return value and function name. Further, all Win32 API definitions look like this: TYPE WINAPI function_name... Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++-- run-command.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5d3d24617e..fd642e4309 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1271,7 +1271,7 @@ static sig_handler_t timer_fn = SIG_DFL; * length to call the signal handler. */ -static __stdcall unsigned ticktack(void *dummy) +static unsigned __stdcall ticktack(void *dummy) { while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { if (timer_fn == SIG_DFL) @@ -1400,7 +1400,7 @@ void mingw_open_html(const char *unixpath) int link(const char *oldpath, const char *newpath) { - typedef BOOL WINAPI (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES); + typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES); static T create_hard_link = NULL; if (!create_hard_link) { create_hard_link = (T) GetProcAddress( diff --git a/run-command.c b/run-command.c index d0833f846e..62bea191d4 100644 --- a/run-command.c +++ b/run-command.c @@ -295,7 +295,7 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const } #ifdef WIN32 -static __stdcall unsigned run_thread(void *data) +static unsigned __stdcall run_thread(void *data) { struct async *async = data; return async->proc(async->fd_for_proc, async->data); From 8d28be57afb7077f61f41e98ee39cf50b6bda249 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 21 Aug 2009 10:34:05 +0200 Subject: [PATCH 0606/3720] Lines of git submodule output on Windows have CRLF Signed-off-by: Johannes Sixt --- t/t7407-submodule-foreach.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 2a527750ce..1f6480a1ae 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -11,6 +11,10 @@ that are currently checked out. . ./test-lib.sh +case $(uname -s) in +*MINGW*) GIT_TEST_CMP="diff -uw";; +esac + test_expect_success 'setup a submodule tree' ' echo file > file && From b7d572cbf2a1f7eed657c4eacf2caa58676e585d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 0607/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Signed-off-by: Johannes Schindelin --- http.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 23b2a1932c..968520b8c4 100644 --- a/http.c +++ b/http.c @@ -1,5 +1,6 @@ #include "http.h" #include "pack.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -129,6 +130,15 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; + *result = system_path(*result); + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -136,17 +146,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 35f39b14eaf0f2cb9a9c171ceb20e1a368785708 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 0608/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index f5ba4e7699..c4f1dfbd7a 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -897,7 +897,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From ae3bedd5cdfa2d374a7ea00150ed113b0845b14a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Jul 2009 22:21:55 +0200 Subject: [PATCH 0609/3720] Skip tests requiring 'iconv' when that is not found Signed-off-by: Johannes Schindelin --- t/t3900-i18n-commit.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 256c4c9701..a0fb178a67 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -64,6 +64,13 @@ test_expect_success 'config to remove customization' ' git config i18n.commitencoding UTF-8 ' +iconv --help 2>/dev/null >/dev/null +test $? = 127 && { + say "No iconv found; skip rest" + test_done + exit +} + test_expect_success 'ISO8859-1 should be shown in UTF-8 now' ' compare_with ISO8859-1 "$TEST_DIRECTORY"/t3900/1-UTF-8.txt ' From 043a43e7ec1ca4aa492406f438d89e1f35df127a Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Mon, 10 Aug 2009 12:47:37 +0200 Subject: [PATCH 0610/3720] Symlink support Add symlink support; with UAC, you may need administrator's privileges to create symlinks, but you can at least read them. As reparse points on Windows differentiate between file and directory links, we just assume that file links are meant for the time being; it might be very hard to determine the type before the target exists, but it is thinkable to change the type on-the-fly. A bridge to cross when we arrive there (read: something for somebody to fix who actually has that problem). Signed-off-by: Johannes Schindelin --- compat/mingw.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- compat/mingw.h | 6 ++--- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6b5b5b2c70..4b1073d49a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,6 +1,7 @@ #include "../git-compat-util.h" #include "win32.h" #include +#include #include "../strbuf.h" #include @@ -170,6 +171,21 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_mode = S_IREAD | S_IFLNK; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + } + FindClose(handle); + } + } return 0; } return -1; @@ -1175,6 +1191,58 @@ int link(const char *oldpath, const char *newpath) return 0; } +int symlink(const char *oldpath, const char *newpath) +{ + typedef BOOL WINAPI (*symlink_fn)(const char*, const char*, DWORD); + static symlink_fn create_symbolic_link = NULL; + if (!create_symbolic_link) { + create_symbolic_link = (symlink_fn) GetProcAddress( + GetModuleHandle("kernel32.dll"), "CreateSymbolicLinkA"); + if (!create_symbolic_link) + create_symbolic_link = (symlink_fn)-1; + } + if (create_symbolic_link == (symlink_fn)-1) { + errno = ENOSYS; + return -1; + } + + if (!create_symbolic_link(newpath, oldpath, 0)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + return 0; +} + +int readlink(const char *path, char *buf, size_t bufsiz) +{ + HANDLE handle = CreateFile(path, GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + + if (handle != INVALID_HANDLE_VALUE) { + unsigned char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + DWORD dummy = 0; + if (DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) { + REPARSE_DATA_BUFFER *b = (REPARSE_DATA_BUFFER *) buffer; + if (b->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + int len = b->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + int offset = b->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + snprintf(buf, bufsiz, "%*ls", len, & b->SymbolicLinkReparseBuffer.PathBuffer[offset]); + CloseHandle(handle); + return len; + } + } + + CloseHandle(handle); + } + + errno = EINVAL; + return -1; +} + char *getpass(const char *prompt) { struct strbuf buf = STRBUF_INIT; @@ -1241,7 +1309,10 @@ struct dirent *mingw_readdir(DIR *dir) /* Set file type, based on WIN32_FIND_DATA */ mdir->dd_dir.d_type = 0; - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + if ((buf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (buf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) + mdir->dd_dir.d_type |= DT_LNK; + else if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) mdir->dd_dir.d_type |= DT_DIR; else mdir->dd_dir.d_type |= DT_REG; diff --git a/compat/mingw.h b/compat/mingw.h index 5b5258bceb..2779bbb1a7 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -68,10 +68,6 @@ struct itimerval { * trivial stubs */ -static inline int readlink(const char *path, char *buf, size_t bufsiz) -{ errno = ENOSYS; return -1; } -static inline int symlink(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) @@ -140,6 +136,8 @@ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); +int symlink(const char *oldpath, const char *newpath); +int readlink(const char *path, char *buf, size_t bufsiz); /* * replacements of existing functions From e8a0ecc3acba68fbcf758553c10ab97eb6be8898 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 18:08:44 +0200 Subject: [PATCH 0611/3720] Fix style of multi-line comments In git.git, we want multi-line comments between single /* and */ in a line. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b1073d49a..4e8402a941 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -151,7 +151,8 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } -/* We keep the do_lstat code in a separate function to avoid recursion. +/* + * We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. */ @@ -191,7 +192,8 @@ static int do_lstat(const char *file_name, struct stat *buf) return -1; } -/* We provide our own lstat/fstat functions, since the provided +/* + * We provide our own lstat/fstat functions, since the provided * lstat/fstat functions are so slow. These stat functions are * tailored for Git's usage (read: fast), and are not meant to be * complete. Note that Git stat()s are redirected to mingw_lstat() @@ -205,7 +207,8 @@ int mingw_lstat(const char *file_name, struct stat *buf) if (!do_lstat(file_name, buf)) return 0; - /* if file_name ended in a '/', Windows returned ENOENT; + /* + * if file_name ended in a '/', Windows returned ENOENT; * try again without trailing slashes */ if (errno != ENOENT) @@ -372,7 +375,8 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout) return errno = EINVAL, error("poll timeout not supported"); } - /* When there is only one fd to wait for, then we pretend that + /* + * When there is only one fd to wait for, then we pretend that * input is available and let the actual wait happen when the * caller invokes read(). */ @@ -412,7 +416,8 @@ repeat: ufds[i].revents = 0; } if (!pending) { - /* The only times that we spin here is when the process + /* + * The only times that we spin here is when the process * that is connected through the pipes is waiting for * its own input data to become available. But since * the process (pack-objects) is itself CPU intensive, @@ -668,7 +673,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (cons == INVALID_HANDLE_VALUE) { - /* There is no console associated with this process. + /* + * There is no console associated with this process. * Since the child is a console process, Windows * would normally create a console window. But * since we'll be redirecting std streams, we do @@ -679,7 +685,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, */ flags = DETACHED_PROCESS; } else { - /* There is already a console. If we specified + /* + * There is already a console. If we specified * DETACHED_PROCESS here, too, Windows would * disassociate the child from the console. * The same is true for CREATE_NO_WINDOW. @@ -1036,7 +1043,8 @@ static int timer_interval; static int one_shot; static sig_handler_t timer_fn = SIG_DFL; -/* The timer works like this: +/* + * The timer works like this: * The thread, ticktack(), is a trivial routine that most of the time * only waits to receive the signal to terminate. The main thread tells * the thread to terminate by setting the timer_event to the signalled @@ -1296,8 +1304,10 @@ struct dirent *mingw_readdir(DIR *dir) DWORD lasterr = GetLastError(); FindClose((HANDLE)dir->dd_handle); dir->dd_handle = (long)INVALID_HANDLE_VALUE; - /* POSIX says you shouldn't set errno when readdir can't - find any more files; so, if another error we leave it set. */ + /* + * POSIX says you shouldn't set errno when readdir can't + * find any more files; so, if another error we leave it set. + */ if (lasterr != ERROR_NO_MORE_FILES) errno = err_win_to_posix(lasterr); return NULL; From 33dc23c8d16a7c99d98d839fb1987a3dda4ac25b Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Sat, 8 Aug 2009 22:44:01 +0200 Subject: [PATCH 0612/3720] On Windows, mark directory hidden when starting with dot. In Windows a file or directory starting with a dot is not automatically hidden. So lets mark it as hidden when such a directory is created. This fixes msysGit issue 288. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- compat/mingw.c | 26 ++++++++++++++++++++++++++ compat/mingw.h | 9 +++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4e8402a941..e1ac77d0ed 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -119,6 +119,32 @@ static int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 2779bbb1a7..0091ba7f3c 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -98,12 +98,6 @@ static inline int fcntl(int fd, int cmd, long arg) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} -#define mkdir mingw_mkdir - static inline int mingw_unlink(const char *pathname) { /* read-only files cannot be removed */ @@ -143,6 +137,9 @@ int readlink(const char *path, char *buf, size_t bufsiz); * replacements of existing functions */ +int mingw_mkdir(const char *path, int mode); +#define mkdir mingw_mkdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 250c0f4ea5657bb041e42cbac26f83cddc71c1d7 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Sat, 8 Aug 2009 22:59:27 +0200 Subject: [PATCH 0613/3720] Make auto-hiding dot-files optional on Windows. Although a file starting with a dot usually ought to be hidden, there could be reasons users do not want it to happen automatically. Original patch by Erik Faye-Lund. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- cache.h | 1 + compat/mingw.c | 3 ++- config.c | 5 +++++ environment.c | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cache.h b/cache.h index a5eeead1e2..767a50e4ed 100644 --- a/cache.h +++ b/cache.h @@ -525,6 +525,7 @@ extern int auto_crlf; extern int read_replace_refs; extern int fsync_object_files; extern int core_preload_index; +extern int hide_dotfiles; enum safe_crlf { SAFE_CRLF_FALSE = 0, diff --git a/compat/mingw.c b/compat/mingw.c index e1ac77d0ed..126b784119 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -131,8 +131,9 @@ static int make_hidden(const char *path) #undef mkdir int mingw_mkdir(const char *path, int mode) { + extern int hide_dotfiles; int ret = mkdir(path); - if (!ret) { + if (!ret && hide_dotfiles) { /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when diff --git a/config.c b/config.c index c644061136..49010e4890 100644 --- a/config.c +++ b/config.c @@ -503,6 +503,11 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 5de6837840..ea1abbf289 100644 --- a/environment.c +++ b/environment.c @@ -50,6 +50,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_replace_parents = 1; +int hide_dotfiles = 1; /* Parallel index stat data preload? */ int core_preload_index = 0; From c1b3bedfaca75caacb072f5636167d23dc21103d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 9 Aug 2009 19:08:05 +0200 Subject: [PATCH 0614/3720] Document the core.hideDotFiles variable Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- Documentation/config.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index cd1781498e..bbb7ee262e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -133,6 +133,10 @@ core.fileMode:: the working copy are ignored; useful on broken filesystems like FAT. See linkgit:git-update-index[1]. True by default. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories whose name starts with a dot as hidden. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful From 5cdb2faf0eb8ba0572b798d7c29071a742a3cb66 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 9 Aug 2009 19:12:17 +0200 Subject: [PATCH 0615/3720] Windows: mark newly-created files whose name starts with a dot as hidden Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- Documentation/config.txt | 2 +- compat/mingw.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index bbb7ee262e..f9fd44e783 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -135,7 +135,7 @@ core.fileMode:: core.hideDotFiles:: (Windows-only) If true (which is the default), mark newly-created - directories whose name starts with a dot as hidden. + directories and files whose name starts with a dot as hidden. core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, diff --git a/compat/mingw.c b/compat/mingw.c index 126b784119..7bb2635b6d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,9 +2,11 @@ #include "win32.h" #include #include +#include #include "../strbuf.h" -#include +extern int hide_dotfiles; +unsigned int _CRT_fmode = _O_BINARY; static int err_win_to_posix(DWORD winerr) { @@ -131,7 +133,6 @@ static int make_hidden(const char *path) #undef mkdir int mingw_mkdir(const char *path, int mode) { - extern int hide_dotfiles; int ret = mkdir(path); if (!ret && hide_dotfiles) { /* @@ -167,6 +168,16 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && hide_dotfiles) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } From f95b4f00a6b3bfb64dae4a9d27bce4b8998562d1 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Wed, 12 Aug 2009 23:40:50 +0200 Subject: [PATCH 0616/3720] Windows: mark newly-created dot files by fopen() as hidden Files starting with a dot are considered "hidden", i.e. you have to ask explicitely to see them. On Windows, this is not done automatically, as Windows has its own mechanism. We already mark dot directories created by mkdir() and dot files created by open() as hidden, so let's do that with fopen(), too (but only if the file was just created, not when it already exists). Naturally, we make this behavior optional on core.hideDotFiles. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 7bb2635b6d..556ed57fea 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -181,6 +181,24 @@ int mingw_open (const char *filename, int oflags, ...) return fd; } +#undef fopen +FILE *mingw_fopen (const char *filename, const char *mode) +{ + int hide = 0; + if (hide_dotfiles && basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); + + FILE *file = fopen(filename, mode); + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; +} + static inline time_t filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; diff --git a/compat/mingw.h b/compat/mingw.h index 0091ba7f3c..0300a14c4a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -143,6 +143,9 @@ int mingw_mkdir(const char *path, int mode); int mingw_open (const char *filename, int oflags, ...); #define open mingw_open +FILE *mingw_fopen (const char *filename, const char *mode); +#define fopen mingw_fopen + char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd From 91b223732572b61f09efc29e62dba5e1c25b4f50 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 10:30:55 +0200 Subject: [PATCH 0617/3720] Fix a few old-style function declarations in compat/ Signed-off-by: Johannes Schindelin --- compat/fnmatch/fnmatch.c | 20 +-- compat/mingw.h | 2 +- compat/nedmalloc/malloc.c.h | 2 +- compat/nedmalloc/nedmalloc.c | 4 +- compat/regex/regex.c | 232 +++++++++++------------------------ 5 files changed, 81 insertions(+), 179 deletions(-) diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 14feac7fe1..1180fc793f 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -130,10 +130,7 @@ extern int errno; /* This function doesn't exist on most systems. */ # if !defined HAVE___STRCHRNUL && !defined _LIBC -static char * -__strchrnul (s, c) - const char *s; - int c; +static char * __strchrnul (const char *s, int c) { char *result = strchr (s, c); if (result == NULL) @@ -153,13 +150,8 @@ __strchrnul (s, c) static int internal_fnmatch __P ((const char *pattern, const char *string, int no_leading_period, int flags)) internal_function; -static int -internal_function -internal_fnmatch (pattern, string, no_leading_period, flags) - const char *pattern; - const char *string; - int no_leading_period; - int flags; +static int internal_function internal_fnmatch (const char *pattern, + const char *string, int no_leading_period, int flags) { register const char *p = pattern, *n = string; register unsigned char c; @@ -476,11 +468,7 @@ internal_fnmatch (pattern, string, no_leading_period, flags) } -int -fnmatch (pattern, string, flags) - const char *pattern; - const char *string; - int flags; +int fnmatch (const char *pattern, const char *string, int flags) { return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); } diff --git a/compat/mingw.h b/compat/mingw.h index 0300a14c4a..1b528daba2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -80,7 +80,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline int getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index 74c42e3162..41b8698ab3 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -1802,7 +1802,7 @@ struct win32_mlock_t static MLOCK_T malloc_global_mutex = { 0, 0, 0}; -static FORCEINLINE long win32_getcurrentthreadid() { +static FORCEINLINE long win32_getcurrentthreadid(void) { #ifdef _MSC_VER #if defined(_M_IX86) long *threadstruct=(long *)__readfsdword(0x18); diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index d9a17a8057..229f942d10 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -159,8 +159,8 @@ struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); } #endif int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); } int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); } -void nedmalloc_stats() THROWSPEC { nedpmalloc_stats(0); } -size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint(0); } +void nedmalloc_stats(void) THROWSPEC { nedpmalloc_stats(0); } +size_t nedmalloc_footprint(void) THROWSPEC { return nedpmalloc_footprint(0); } void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); } void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); } diff --git a/compat/regex/regex.c b/compat/regex/regex.c index 67d5c370a0..68de236af1 100644 --- a/compat/regex/regex.c +++ b/compat/regex/regex.c @@ -64,8 +64,7 @@ extern char *re_syntax_table; static char re_syntax_table[CHAR_SET_SIZE]; -static void -init_syntax_once () +static void init_syntax_once(void) { register int c; static int done = 0; @@ -380,10 +379,7 @@ typedef enum } while (0) #ifdef DEBUG -static void -extract_number (dest, source) - int *dest; - unsigned char *source; +static void extract_number(int *dest, unsigned char *source) { int temp = SIGN_EXTEND_CHAR (*(source + 1)); *dest = *source & 0377; @@ -407,10 +403,8 @@ extract_number (dest, source) } while (0) #ifdef DEBUG -static void -extract_number_and_incr (destination, source) - int *destination; - unsigned char **source; +static void extract_number_and_incr(int *destination, + unsigned char **source) { extract_number (destination, *source); *source += 2; @@ -455,9 +449,7 @@ extern void printchar (); /* Print the fastmap in human-readable form. */ -void -print_fastmap (fastmap) - char *fastmap; +void print_fastmap(char *fastmap) { unsigned was_a_range = 0; unsigned i = 0; @@ -487,10 +479,8 @@ print_fastmap (fastmap) /* Print a compiled pattern string in human-readable form, starting at the START pointer into it and ending just before the pointer END. */ -void -print_partial_compiled_pattern (start, end) - unsigned char *start; - unsigned char *end; +void print_partial_compiled_pattern(unsigned char *start, + unsigned char *end) { int mcnt, mcnt2; unsigned char *p = start; @@ -695,9 +685,7 @@ print_partial_compiled_pattern (start, end) } -void -print_compiled_pattern (bufp) - struct re_pattern_buffer *bufp; +void print_compiled_pattern(struct re_pattern_buffer *bufp) { unsigned char *buffer = bufp->buffer; @@ -722,13 +710,9 @@ print_compiled_pattern (bufp) } -void -print_double_string (where, string1, size1, string2, size2) - const char *where; - const char *string1; - const char *string2; - int size1; - int size2; +void print_double_string(const char *where, + const char *string1, int size1, + const char *string2, int size2) { unsigned this_char; @@ -777,9 +761,7 @@ reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; The argument SYNTAX is a bit mask comprised of the various bits defined in regex.h. We return the old syntax. */ -reg_syntax_t -re_set_syntax (syntax) - reg_syntax_t syntax; +reg_syntax_t re_set_syntax(reg_syntax_t syntax) { reg_syntax_t ret = re_syntax_options; @@ -1031,12 +1013,9 @@ typedef struct The `fastmap' and `newline_anchor' fields are neither examined nor set. */ -static reg_errcode_t -regex_compile (pattern, size, syntax, bufp) - const char *pattern; - int size; - reg_syntax_t syntax; - struct re_pattern_buffer *bufp; +static reg_errcode_t regex_compile(const char *pattern, + int size, reg_syntax_t syntax, + struct re_pattern_buffer *bufp) { /* We fetch characters from PATTERN here. Even though PATTERN is `char *' (i.e., signed), we declare these variables as unsigned, so @@ -2036,11 +2015,8 @@ regex_compile (pattern, size, syntax, bufp) /* Store OP at LOC followed by two-byte integer parameter ARG. */ -static void -store_op1 (op, loc, arg) - re_opcode_t op; - unsigned char *loc; - int arg; +static void store_op1(re_opcode_t op, unsigned char *loc, + int arg) { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg); @@ -2049,11 +2025,8 @@ store_op1 (op, loc, arg) /* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ -static void -store_op2 (op, loc, arg1, arg2) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; +static void store_op2(re_opcode_t op, unsigned char *loc, + int arg1, int arg2) { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg1); @@ -2064,12 +2037,8 @@ store_op2 (op, loc, arg1, arg2) /* Copy the bytes from LOC to END to open up three bytes of space at LOC for OP followed by two-byte integer parameter ARG. */ -static void -insert_op1 (op, loc, arg, end) - re_opcode_t op; - unsigned char *loc; - int arg; - unsigned char *end; +static void insert_op1(re_opcode_t op, unsigned char *loc, + int arg, unsigned char *end) { register unsigned char *pfrom = end; register unsigned char *pto = end + 3; @@ -2083,12 +2052,8 @@ insert_op1 (op, loc, arg, end) /* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ -static void -insert_op2 (op, loc, arg1, arg2, end) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; - unsigned char *end; +static void insert_op2(re_opcode_t op, unsigned char *loc, + int arg1, int arg2, unsigned char *end) { register unsigned char *pfrom = end; register unsigned char *pto = end + 5; @@ -2104,10 +2069,8 @@ insert_op2 (op, loc, arg1, arg2, end) after an alternative or a begin-subexpression. We assume there is at least one character before the ^. */ -static boolean -at_begline_loc_p (pattern, p, syntax) - const char *pattern, *p; - reg_syntax_t syntax; +static boolean at_begline_loc_p(const char *pattern, + const char *p, reg_syntax_t syntax) { const char *prev = p - 2; boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; @@ -2123,10 +2086,8 @@ at_begline_loc_p (pattern, p, syntax) /* The dual of at_begline_loc_p. This one is for $. We assume there is at least one character after the $, i.e., `P < PEND'. */ -static boolean -at_endline_loc_p (p, pend, syntax) - const char *p, *pend; - int syntax; +static boolean at_endline_loc_p(const char *p, + const char *pend, int syntax) { const char *next = p; boolean next_backslash = *next == '\\'; @@ -2145,10 +2106,8 @@ at_endline_loc_p (p, pend, syntax) /* Returns true if REGNUM is in one of COMPILE_STACK's elements and false if it's not. */ -static boolean -group_in_compile_stack (compile_stack, regnum) - compile_stack_type compile_stack; - regnum_t regnum; +static boolean group_in_compile_stack(compile_stack_type + compile_stack, regnum_t regnum) { int this_element; @@ -2173,12 +2132,9 @@ group_in_compile_stack (compile_stack, regnum) We use these short variable names so we can use the same macros as `regex_compile' itself. */ -static reg_errcode_t -compile_range (p_ptr, pend, translate, syntax, b) - const char **p_ptr, *pend; - char *translate; - reg_syntax_t syntax; - unsigned char *b; +static reg_errcode_t compile_range(const char **p_ptr, + const char *pend, char *translate, + reg_syntax_t syntax, unsigned char *b) { unsigned this_char; @@ -2505,9 +2461,7 @@ typedef struct Returns 0 if we succeed, -2 if an internal error. */ -int -re_compile_fastmap (bufp) - struct re_pattern_buffer *bufp; +int re_compile_fastmap(struct re_pattern_buffer *bufp) { int j, k; fail_stack_type fail_stack; @@ -2790,12 +2744,10 @@ re_compile_fastmap (bufp) PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ -void -re_set_registers (bufp, regs, num_regs, starts, ends) - struct re_pattern_buffer *bufp; - struct re_registers *regs; - unsigned num_regs; - regoff_t *starts, *ends; +void re_set_registers(struct re_pattern_buffer *bufp, + struct re_registers *regs, + unsigned num_regs, + regoff_t *starts, regoff_t *ends) { if (num_regs) { @@ -2817,12 +2769,10 @@ re_set_registers (bufp, regs, num_regs, starts, ends) /* Like re_search_2, below, but only one string is specified, and doesn't let you say where to stop matching. */ -int -re_search (bufp, string, size, startpos, range, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, startpos, range; - struct re_registers *regs; +int re_search(struct re_pattern_buffer *bufp, + const char *string, int size, + int startpos, int range, + struct re_registers *regs) { return re_search_2 (bufp, NULL, 0, string, size, startpos, range, regs, size); @@ -2850,15 +2800,11 @@ re_search (bufp, string, size, startpos, range, regs) found, -1 if no match, or -2 if error (such as failure stack overflow). */ -int -re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int startpos; - int range; - struct re_registers *regs; - int stop; +int re_search_2(struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int startpos, int range, + struct re_registers *regs, int stop) { int val; register char *fastmap = bufp->fastmap; @@ -3109,12 +3055,9 @@ typedef union #ifndef emacs /* Emacs never uses this. */ /* re_match is like re_match_2 except it takes only a single string. */ -int -re_match (bufp, string, size, pos, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, pos; - struct re_registers *regs; +int re_match(struct re_pattern_buffer *bufp, + const char *string, int size, int pos, + struct re_registers *regs) { return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); } @@ -3134,14 +3077,10 @@ re_match (bufp, string, size, pos, regs) failure stack overflowing). Otherwise, we return the length of the matched substring. */ -int -re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int pos; - struct re_registers *regs; - int stop; +int re_match_2(struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, struct re_registers *regs, int stop) { /* General temporaries. */ int mcnt; @@ -4330,10 +4269,9 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) We don't handle duplicates properly (yet). */ -static boolean -group_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; +static boolean group_match_null_string_p(unsigned char **p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; /* Point to after the args to the start_memory. */ @@ -4439,10 +4377,9 @@ group_match_null_string_p (p, end, reg_info) It expects P to be the first byte of a single alternative and END one byte past the last. The alternative can contain groups. */ -static boolean -alt_match_null_string_p (p, end, reg_info) - unsigned char *p, *end; - register_info_type *reg_info; +static boolean alt_match_null_string_p(unsigned char *p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; unsigned char *p1 = p; @@ -4476,10 +4413,9 @@ alt_match_null_string_p (p, end, reg_info) Sets P to one after the op and its arguments, if any. */ -static boolean -common_op_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; +static boolean common_op_match_null_string_p(unsigned char **p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; boolean ret; @@ -4564,13 +4500,8 @@ common_op_match_null_string_p (p, end, reg_info) /* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN bytes; nonzero otherwise. */ -static int -bcmp_translate( - unsigned char *s1, - unsigned char *s2, - int len, - char *translate -) +static int bcmp_translate(unsigned char *s1, unsigned char *s2, + int len, char *translate) { register unsigned char *p1 = s1, *p2 = s2; while (len) @@ -4592,11 +4523,8 @@ bcmp_translate( We call regex_compile to do the actual compilation. */ -const char * -re_compile_pattern (pattern, length, bufp) - const char *pattern; - int length; - struct re_pattern_buffer *bufp; +const char *re_compile_pattern(const char *pattern, + int length, struct re_pattern_buffer *bufp) { reg_errcode_t ret; @@ -4625,9 +4553,7 @@ re_compile_pattern (pattern, length, bufp) /* BSD has one and only one pattern buffer. */ static struct re_pattern_buffer re_comp_buf; -char * -re_comp (s) - const char *s; +char *re_comp(const char *s) { reg_errcode_t ret; @@ -4663,9 +4589,7 @@ re_comp (s) } -int -re_exec (s) - const char *s; +int re_exec(const char *s) { const int len = strlen (s); return @@ -4711,11 +4635,7 @@ re_exec (s) It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for the return codes and their meanings.) */ -int -regcomp (preg, pattern, cflags) - regex_t *preg; - const char *pattern; - int cflags; +int regcomp(regex_t *preg, const char *pattern, int cflags) { reg_errcode_t ret; unsigned syntax @@ -4786,13 +4706,9 @@ regcomp (preg, pattern, cflags) We return 0 if we find a match and REG_NOMATCH if not. */ -int -regexec (preg, string, nmatch, pmatch, eflags) - const regex_t *preg; - const char *string; - size_t nmatch; - regmatch_t pmatch[]; - int eflags; +int regexec(const regex_t *preg, const char *string, + size_t nmatch, regmatch_t pmatch[], + int eflags) { int ret; struct re_registers regs; @@ -4892,9 +4808,7 @@ regerror(int errcode, const regex_t *preg, /* Free dynamically allocated space used by PREG. */ -void -regfree (preg) - regex_t *preg; +void regfree(regex_t *preg) { if (preg->buffer != NULL) free (preg->buffer); From 12b6e8cb65aa65f22f243a5b7d347175bbf3fd20 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 10:31:29 +0200 Subject: [PATCH 0618/3720] compat/mingw.c: Fix declaration after instruction Signed-off-by: Johannes Schindelin --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 556ed57fea..9e0f5e0ffb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -185,10 +185,11 @@ int mingw_open (const char *filename, int oflags, ...) FILE *mingw_fopen (const char *filename, const char *mode) { int hide = 0; + FILE *file; if (hide_dotfiles && basename((char*)filename)[0] == '.') hide = access(filename, F_OK); - FILE *file = fopen(filename, mode); + file = fopen(filename, mode); /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when From a2546af6686b7f55ce21660821dba2bde641efcf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 09:59:58 +0200 Subject: [PATCH 0619/3720] MinGW means that we have gcc, so we can add gcc-specific compiler options These were suggested by Junio at some stage. Signed-off-by: Johannes Schindelin --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index fea237bc80..8f1f157e4f 100644 --- a/Makefile +++ b/Makefile @@ -980,6 +980,9 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_REGEX = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" + # We have GCC, so let's make use of those nice options + COMPAT_CFLAGS += -Werror -Wno-pointer-to-int-cast \ + -Wold-style-definition -Wdeclaration-after-statement COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe From c124c9679255ad759d3441c5fd946a249fd39be3 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 16 Aug 2009 13:53:30 +0800 Subject: [PATCH 0620/3720] Define SNPRINTF_SIZE_CORR=1 for Microsoft Visual C++ The Microsoft C runtime's vsnprintf function does not add NUL at the end of the buffer. Further, Microsoft deprecated vsnprintf in favor of _vsnprintf, so add a #define to that end. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/snprintf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index e1e0e7543d..28b02c6837 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -9,7 +9,7 @@ * always have room for a trailing NUL byte. */ #ifndef SNPRINTF_SIZE_CORR -#if defined(WIN32) && (!defined(__GNUC__) || __GNUC__ < 4) +#if defined(WIN32) && defined(__GNUC__) && __GNUC__ < 4 || defined(_MSC_VER) #define SNPRINTF_SIZE_CORR 1 #else #define SNPRINTF_SIZE_CORR 0 @@ -17,6 +17,11 @@ #endif #undef vsnprintf + +#if defined(_MSC_VER) +#define vsnprintf _vsnprintf +#endif + int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { char *s; From 62d2d6829cc7adab30cb2b52bc90a0d70f6952c1 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 17 Aug 2009 14:52:01 +0800 Subject: [PATCH 0621/3720] mingw.c: Use the O_BINARY flag to open files On Windows, non-text files must be opened using the O_BINARY flag. MinGW does this for us automatically, but Microsoft Visual C++ does not. So let's be explicit. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9e0f5e0ffb..10d67964ed 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -161,7 +161,7 @@ int mingw_open (const char *filename, int oflags, ...) if (!strcmp(filename, "/dev/null")) filename = "nul"; - fd = open(filename, oflags, mode); + fd = open(filename, oflags | O_BINARY, mode); if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { DWORD attrs = GetFileAttributes(filename); @@ -354,7 +354,7 @@ int mkstemp(char *template) char *filename = mktemp(template); if (filename == NULL) return -1; - return open(filename, O_RDWR | O_CREAT, 0600); + return open(filename, O_RDWR | O_CREAT | O_BINARY, 0600); } int gettimeofday(struct timeval *tv, void *tz) From 127aa63757870526b106c045310a3b6c4cee0324 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 18:40:30 +0200 Subject: [PATCH 0622/3720] git am: accept patches downloaded from GMane GMane has this wonderful feature that you can download the raw mails, but the mails do not fully conform to the mbox format, as they do not start with a "From ..." line. But they start with another tell tale we can easily detect. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index c132f50da5..cca351288e 100755 --- a/git-am.sh +++ b/git-am.sh @@ -172,7 +172,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "*) + "From "* | "From: "* | "Path:news.gmane.org"*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 8ed9ebe27ae70f634f4f734aa581ca796ccf906a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 14 Oct 2009 11:51:03 -0700 Subject: [PATCH 0623/3720] CRLF in info/grafts causes parse error "Yann Dirson" writes: > When creating an info/grafts under windows, one typically gets a CRLF file. > Then: > > * gitk loudly complains about "bad graft data" > * "git log > /dev/null" does not report any problem > * "git log > foo" does report the problem on sdterr, but exit code is still 0 > > Recreating the graft as a LF file (eg with "echo" or "printf") causes the > graft to be properly interpreted. I do not see any reason to forbid trailing CR at the end of the line (for that matter, any trailing whitespaces) in the said file. How about doing this? commit.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) --- commit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commit.c b/commit.c index fedbd5e526..0db2124f98 100644 --- a/commit.c +++ b/commit.c @@ -132,8 +132,8 @@ struct commit_graft *read_graft_line(char *buf, int len) int i; struct commit_graft *graft = NULL; - if (buf[len-1] == '\n') - buf[--len] = 0; + while (isspace(buf[len-1])) + buf[--len] = '\0'; if (buf[0] == '#' || buf[0] == '\0') return NULL; if ((len + 1) % 41) { From cd4896c3b6f79d7eec4a17e7f23d1ea446bd6323 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0624/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 8f1f157e4f..1acad5fd5b 100644 --- a/Makefile +++ b/Makefile @@ -1601,6 +1601,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1608,6 +1609,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From ccc5cdf764be2d46b91a5840de5edd763851bf91 Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Mon, 26 Oct 2009 23:39:31 +0100 Subject: [PATCH 0625/3720] Replace dir separator in symlinks It seems quite a few windows utilities cannot handle '../' in symlinks, so we replace every / with a \. While at it, replace make_backslash_path with a thread-safe version. Signed-off-by: Thorvald Natvig Signed-off-by: Johannes Schindelin --- compat/mingw.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 10d67964ed..2424380cba 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1213,9 +1213,8 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler) return old; } -static const char *make_backslash_path(const char *path) +static const char *make_backslash_path(const char *path, char *buf) { - static char buf[PATH_MAX + 1]; char *c; if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) @@ -1230,7 +1229,8 @@ static const char *make_backslash_path(const char *path) void mingw_open_html(const char *unixpath) { - const char *htmlpath = make_backslash_path(unixpath); + char buf[PATH_MAX + 1]; + const char *htmlpath = make_backslash_path(unixpath, buf); printf("Launching default browser to display HTML ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } @@ -1260,6 +1260,8 @@ int symlink(const char *oldpath, const char *newpath) { typedef BOOL WINAPI (*symlink_fn)(const char*, const char*, DWORD); static symlink_fn create_symbolic_link = NULL; + char buf[PATH_MAX + 1]; + if (!create_symbolic_link) { create_symbolic_link = (symlink_fn) GetProcAddress( GetModuleHandle("kernel32.dll"), "CreateSymbolicLinkA"); @@ -1271,7 +1273,7 @@ int symlink(const char *oldpath, const char *newpath) return -1; } - if (!create_symbolic_link(newpath, oldpath, 0)) { + if (!create_symbolic_link(newpath, make_backslash_path(oldpath, buf), 0)) { errno = err_win_to_posix(GetLastError()); return -1; } @@ -1295,7 +1297,11 @@ int readlink(const char *path, char *buf, size_t bufsiz) if (b->ReparseTag == IO_REPARSE_TAG_SYMLINK) { int len = b->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); int offset = b->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + int i; snprintf(buf, bufsiz, "%*ls", len, & b->SymbolicLinkReparseBuffer.PathBuffer[offset]); + for (i = 0; i < len; i++) + if (buf[i] == '\\') + buf[i] = '/'; CloseHandle(handle); return len; } From 9ba38c833b5bbe06f74f19bc6911036ef6a9fb09 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 5 Oct 2009 10:22:18 +0200 Subject: [PATCH 0626/3720] Make the MSVC projects use PDB/IDB files named after the project Instead of having all PDB files for all projects named "vc90.pdb", name them after the respective project to make the relation more clear (and to avoid name clashes when copying files around). Signed-off-by: Sebastian Schuberth Acked-by: Marius Storm-Olsen Signed-off-by: Johannes Schindelin --- contrib/buildsystems/Generators/Vcproj.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/buildsystems/Generators/Vcproj.pm b/contrib/buildsystems/Generators/Vcproj.pm index be94ba18d2..cfa74adcc2 100644 --- a/contrib/buildsystems/Generators/Vcproj.pm +++ b/contrib/buildsystems/Generators/Vcproj.pm @@ -178,6 +178,7 @@ sub createLibProject { MinimalRebuild="true" RuntimeLibrary="1" UsePrecompiledHeader="0" + ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb" WarningLevel="3" DebugInformationFormat="3" /> @@ -244,6 +245,7 @@ sub createLibProject { RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" + ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb" WarningLevel="3" DebugInformationFormat="3" /> @@ -401,6 +403,7 @@ sub createAppProject { MinimalRebuild="true" RuntimeLibrary="1" UsePrecompiledHeader="0" + ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb" WarningLevel="3" DebugInformationFormat="3" /> @@ -472,6 +475,7 @@ sub createAppProject { RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" + ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb" WarningLevel="3" DebugInformationFormat="3" /> From 7e9e93bc6764d65e26a5cb4f3fc6462c52ab075d Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 19 Oct 2009 18:28:50 +0200 Subject: [PATCH 0627/3720] Use faster byte swapping when compiling with MSVC When compiling with MSVC on x86-compatible, use an intrinsic for byte swapping. In contrast to the GCC path, we do not prefer inline assembly here as it is not supported for the x64 platform. Signed-off-by: Sebastian Schuberth Signed-off-by: Johannes Schindelin --- compat/bswap.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compat/bswap.h b/compat/bswap.h index 5cc4acbfcc..279e0b48b1 100644 --- a/compat/bswap.h +++ b/compat/bswap.h @@ -28,6 +28,16 @@ static inline uint32_t default_swab32(uint32_t val) } \ __res; }) +#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + +#include + +#define bswap32(x) _byteswap_ulong(x) + +#endif + +#ifdef bswap32 + #undef ntohl #undef htonl #define ntohl(x) bswap32(x) From 1abf3a543677b83852b21f96d02a4baeebf49567 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Tue, 27 Oct 2009 12:13:05 +0100 Subject: [PATCH 0628/3720] Do not try to remove directories when removing old links When building Git with MSVC on Windows, directories named after the Git alias are created for the output files, e.g. there is a "git-merge-index" directory next to the "git-merge-index.exe" executable in the build root. Previously, "make all" just checked if "git-merge-index" and "git-merge-index.exe" are the same file, and if not, tried to remove "git-merge-index". This fails in the case of "git-merge-index" being a directory, which is why this is checked now. Signed-off-by: Sebastian Schuberth Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1acad5fd5b..393d4b1f2a 100644 --- a/Makefile +++ b/Makefile @@ -1378,7 +1378,7 @@ SHELL = $(SHELL_PATH) all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS ifneq (,$X) - $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';) + $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';) endif all:: From 915ac13797b2224295a21233e8ca3d6981a02fac Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0629/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 1b528daba2..adf5ff5686 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -5,6 +5,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -70,17 +71,17 @@ struct itimerval { static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid(void) +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -106,7 +107,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -126,7 +127,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 71d16883000440739a8b4f78435fefed1d17b974 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0630/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index adf5ff5686..45cb239872 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -11,12 +11,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From f1d8529445e627801b433fffcc034ad90a7e99ff Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0631/3720] core.hidedotfiles: only hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 2 ++ builtin-init-db.c | 1 + cache.h | 8 +++++++- compat/mingw.c | 16 ++++++++++++---- compat/mingw.h | 3 +++ config.c | 4 ++++ environment.c | 2 +- git-compat-util.h | 4 ++++ 8 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f9fd44e783..6370d6f6f7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -136,6 +136,8 @@ core.fileMode:: core.hideDotFiles:: (Windows-only) If true (which is the default), mark newly-created directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, diff --git a/builtin-init-db.c b/builtin-init-db.c index dd84caecbc..8640643675 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -298,6 +298,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 767a50e4ed..d3bfe0d36f 100644 --- a/cache.h +++ b/cache.h @@ -525,7 +525,13 @@ extern int auto_crlf; extern int read_replace_refs; extern int fsync_object_files; extern int core_preload_index; -extern int hide_dotfiles; + +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; enum safe_crlf { SAFE_CRLF_FALSE = 0, diff --git a/compat/mingw.c b/compat/mingw.c index 2424380cba..45c5a19aaa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -4,8 +4,8 @@ #include #include #include "../strbuf.h" +#include "../cache.h" -extern int hide_dotfiles; unsigned int _CRT_fmode = _O_BINARY; static int err_win_to_posix(DWORD winerr) @@ -130,11 +130,17 @@ static int make_hidden(const char *path) return -1; } +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + #undef mkdir int mingw_mkdir(const char *path, int mode) { int ret = mkdir(path); - if (!ret && hide_dotfiles) { + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when @@ -168,7 +174,8 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } - if ((oflags & O_CREAT) && fd >= 0 && hide_dotfiles) { + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when @@ -186,7 +193,8 @@ FILE *mingw_fopen (const char *filename, const char *mode) { int hide = 0; FILE *file; - if (hide_dotfiles && basename((char*)filename)[0] == '.') + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') hide = access(filename, F_OK); file = fopen(filename, mode); diff --git a/compat/mingw.h b/compat/mingw.h index 45cb239872..364cc72bae 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -231,6 +231,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 49010e4890..c8cdb81633 100644 --- a/config.c +++ b/config.c @@ -504,6 +504,10 @@ static int git_default_core_config(const char *var, const char *value) } if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } hide_dotfiles = git_config_bool(var, value); return 0; } diff --git a/environment.c b/environment.c index ea1abbf289..ccbae176ea 100644 --- a/environment.c +++ b/environment.c @@ -50,7 +50,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_replace_parents = 1; -int hide_dotfiles = 1; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index ef60803384..db19559bc3 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -464,4 +464,8 @@ void git_qsort(void *base, size_t nmemb, size_t size, */ int unlink_or_warn(const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From c8364b54aacb2c1c6cbf4200618a5241764c13d3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0632/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 45c5a19aaa..33b6b80e05 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -134,6 +134,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 9e44c8e5267528713a26f22d4355327076df29ec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Jan 2010 18:16:25 +0100 Subject: [PATCH 0633/3720] Revert "git am: accept patches downloaded from GMane" This reverts commit 127aa63757870526b106c045310a3b6c4cee0324. As pointed out by Junio, this patch was obsoleted by 0fcb2ca. --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index cca351288e..c132f50da5 100755 --- a/git-am.sh +++ b/git-am.sh @@ -172,7 +172,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "* | "Path:news.gmane.org"*) + "From "* | "From: "*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 2a3fb596222c33c331ab82548501c03b0c68ae35 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Sat, 23 Jan 2010 15:20:28 +0100 Subject: [PATCH 0634/3720] If deriving SVN_SSH from GIT_SSH on msys, also add quotes In contrast to GIT_SSH, SVN_SSH requires quotes for paths that contain spaces. As GIT_SSH will not work if it contains quotes, it is safe to assume it never contains quotes. Also, adding quotes to SVN_SSH for paths that do not contain spaces does no harm. So we always add quotes when deriving SVN_SSH from GIT_SSH. This fixes msysGit issue 385, see http://code.google.com/p/msysgit/issues/detail?id=385 Signed-off-by: Sebastian Schuberth Signed-off-by: Johannes Schindelin --- git-svn.perl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-svn.perl b/git-svn.perl index b321c968af..4f7dc2b73b 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -26,6 +26,7 @@ if (! exists $ENV{SVN_SSH}) { $ENV{SVN_SSH} = $ENV{GIT_SSH}; if ($^O eq 'msys') { $ENV{SVN_SSH} =~ s/\\/\\\\/g; + $ENV{SVN_SSH} =~ s/(.*)/"$1"/; } } } From b27a86a21e5b42722c0c8abb7491f032c5549778 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0635/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 2539a7bdb81dcc920c97837a9bfb9d4c4e1ac280 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Mon, 15 Feb 2010 22:36:28 +0100 Subject: [PATCH 0636/3720] [PATCH] fix threaded grep for machines with only one cpu In case the machine has only one cpu the mutex initialization was skipped. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- builtin-grep.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 26d4deb1cc..644051c200 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -220,12 +220,6 @@ static void start_threads(struct grep_opt *opt) { int i; - pthread_mutex_init(&grep_mutex, NULL); - pthread_mutex_init(&read_sha1_mutex, NULL); - pthread_cond_init(&cond_add, NULL); - pthread_cond_init(&cond_write, NULL); - pthread_cond_init(&cond_result, NULL); - for (i = 0; i < ARRAY_SIZE(todo); i++) { strbuf_init(&todo[i].out, 0); } @@ -880,6 +874,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; + pthread_mutex_init(&grep_mutex, NULL); + pthread_mutex_init(&read_sha1_mutex, NULL); + pthread_cond_init(&cond_add, NULL); + pthread_cond_init(&cond_write, NULL); + pthread_cond_init(&cond_result, NULL); + if (use_threads) start_threads(&opt); #else From 51cb20e7373c951f6b0c6c9368d196c26c41c443 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0637/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index f11f98c3ce..90541a39c6 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index afd3053f96..f6a159044f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -776,6 +776,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From d2d1e96d8aa6d9e76d070ddc1a278f1126446bc0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 17 Feb 2010 02:12:43 +0100 Subject: [PATCH 0638/3720] Revert "[PATCH] fix threaded grep for machines with only one cpu" This reverts commit 2539a7bdb81dcc920c97837a9bfb9d4c4e1ac280. --- builtin-grep.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 644051c200..26d4deb1cc 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -220,6 +220,12 @@ static void start_threads(struct grep_opt *opt) { int i; + pthread_mutex_init(&grep_mutex, NULL); + pthread_mutex_init(&read_sha1_mutex, NULL); + pthread_cond_init(&cond_add, NULL); + pthread_cond_init(&cond_write, NULL); + pthread_cond_init(&cond_result, NULL); + for (i = 0; i < ARRAY_SIZE(todo); i++) { strbuf_init(&todo[i].out, 0); } @@ -874,12 +880,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; - pthread_mutex_init(&grep_mutex, NULL); - pthread_mutex_init(&read_sha1_mutex, NULL); - pthread_cond_init(&cond_add, NULL); - pthread_cond_init(&cond_write, NULL); - pthread_cond_init(&cond_result, NULL); - if (use_threads) start_threads(&opt); #else From 3daa340643aada6f27d3f3acf5c91549d710019a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 16 Feb 2010 15:59:43 -0800 Subject: [PATCH 0639/3720] Fix use of mutex in threaded grep The program can decide at runtime not to use threading even if the support is compiled in. In such a case, mutexes are not necessary and left uninitialized. But the code incorrectly tried to take and release the read_sha1_mutex unconditionally. Signed-off-by: Junio C Hamano Acked-by: Fredrik Kuivinen Diagnosed-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- builtin-grep.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 26d4deb1cc..8cec8b6e38 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -408,15 +408,25 @@ static int pathspec_matches(const char **paths, const char *name, int max_depth) return 0; } +static void *read_sha1_file_locked(const unsigned char *sha1, enum object_type *type, unsigned long *size) +{ + void *data; + + if (use_threads) { + read_sha1_lock(); + data = read_sha1_file(sha1, type, size); + read_sha1_unlock(); + } else { + data = read_sha1_file(sha1, type, size); + } + return data; +} + static void *load_sha1(const unsigned char *sha1, unsigned long *size, const char *name) { enum object_type type; - char *data; - - read_sha1_lock(); - data = read_sha1_file(sha1, &type, size); - read_sha1_unlock(); + void *data = read_sha1_file_locked(sha1, &type, size); if (!data) error("'%s': unable to read %s", name, sha1_to_hex(sha1)); @@ -605,10 +615,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths, void *data; unsigned long size; - read_sha1_lock(); - data = read_sha1_file(entry.sha1, &type, &size); - read_sha1_unlock(); - + data = read_sha1_file_locked(entry.sha1, &type, &size); if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); From c44de514e5db1ab4ef77c621199b1faffa624061 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0640/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 90b60aea820afcec62f73f15f279e918261c6935 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0641/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4e409f0c2b..265646f735 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -157,6 +157,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index ab7cf886bb..f66c83166b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -112,14 +112,6 @@ static inline int fcntl(int fd, int cmd, long arg) * simple adaptors */ -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -175,6 +167,9 @@ int readlink(const char *path, char *buf, size_t bufsiz); int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 918092c518a526ab8bde8cbbe62096c3b2ea6b17 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0642/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 265646f735..e637209baf 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -7,6 +7,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -160,9 +161,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1220,7 +1236,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 7a7e4a52085cf3e82cf7b697787fc3e79bd03aaa Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0643/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 8dfb578d003da0d4f07466d7b9fbbb14f5d09a74 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0644/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 89f5b0c385af73ec27499c41d42c45e540203ef3 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0645/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From c31440e711dd6d2910ad70c9ba0ed6f0e2292862 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Feb 2010 12:42:56 +0100 Subject: [PATCH 0646/3720] Print RUNTIME_PREFIX warning only when GIT_TRACE is set When RUNTIME_PREFIX is enabled, the installation prefix is derived by trying a limited set of known locations where the git executable can reside. If none of these is found, a warning is emitted. When git is built in a directory that matches neither of these known names, the warning would always be emitted when the uninstalled executable is run. This is a problem on Windows, where gitk picks the uninstalled git when invoked from the build directory and gets confused by the warning. Print the warning only when GIT_TRACE is set. Signed-off-by: Johannes Sixt Signed-off-by: Johannes Schindelin --- exec_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec_cmd.c b/exec_cmd.c index 408e4e55e1..b2c07c70ce 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -28,7 +28,7 @@ const char *system_path(const char *path) !(prefix = strip_path_suffix(argv0_path, BINDIR)) && !(prefix = strip_path_suffix(argv0_path, "git"))) { prefix = PREFIX; - fprintf(stderr, "RUNTIME_PREFIX requested, " + trace_printf("RUNTIME_PREFIX requested, " "but prefix computation failed. " "Using static fallback '%s'.\n", prefix); } From 6a5f4e550b8b7e8140c0792eab123ebd90f6bb1f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0647/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index e637209baf..5326a1bd9a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -158,6 +159,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -178,6 +227,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1277,6 +1330,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 03a5d44342b5427244592fe1d1cf73a5012dfd9f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0648/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 5326a1bd9a..d7d8970111 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -234,6 +234,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f66c83166b..4650d8a882 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -170,6 +170,9 @@ int mingw_mkdir(const char *path, int mode); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 4d055078ccc7dfbd844aa8862dba79edbd6a003f Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0649/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From 88da20e1eb3caf3f037476708737b37a1bb739d3 Mon Sep 17 00:00:00 2001 From: Michael Lukashov Date: Sun, 28 Feb 2010 03:03:12 -0600 Subject: [PATCH 0650/3720] Makefile: fix definition of $(TEST_PROGRAMS) on Windows Commit ea92519 (build dashless "bin-wrappers" directory similar to installed bindir, 2009-12-02) replaced the definition of TEST_PROGRAMS with a macro: TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X)) and commit daa99a9 (Makefile: make sure test helpers are rebuilt when headers change, 2010-01-26) moved the (unchanged, non-macro) definition of TEST_PROGRAMS earlier so it could be used in two different sections of the Makefile. The merge 225f78 resolving these two changes unfortunately snuck in an optimization while at it: it replaced the delayed-evaluation = operator with an immediate := assignment: TEST_PROGRAMS := $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X)) Such a change would have been safe when TEST_PROGRAMS was defined towards the bottom of the makefile, but in its new location before the platform-specific definitions, $(X) is not yet defined. Thus the following error occurs when trying to compile Git in Windows: make: *** No rule to make target `test-chmtime', needed by `all'. Stop. or if X is set to a nonempty value in config.mak. So change the operator back to =. This makes TEST_PROGRAMS more similar to PROGRAMS and the other macros defined with delayed evaluation in that section. Thanks to Junio for the analysis. Signed-off-by: Michael Lukashov Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b6f097e1f2..498e5e762c 100644 --- a/Makefile +++ b/Makefile @@ -393,7 +393,7 @@ TEST_PROGRAMS_NEED_X += test-sha1 TEST_PROGRAMS_NEED_X += test-sigchain TEST_PROGRAMS_NEED_X += test-index-version -TEST_PROGRAMS := $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X)) +TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X)) # List built-in command $C whose implementation cmd_$C() is not in # builtin/$C.o but is linked in as part of some other command. From 1d1755510527ca192bce200c92286bf568ec3ee9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 28 Feb 2010 23:31:21 -0800 Subject: [PATCH 0651/3720] t0050: mark non-working test as such The test is to prepare an empty file "camelcase" in the index, remove and replace it with another file "CamelCase" with "1" as its contents in the working tree, and add it to the index, in a repository configured to be case insensitive. However, the test actually checked ls-files knows about a pathname that matches "camelcase" case insensitively. It didn't check if the added contents actually was the updated one. Mark the test as non-working. Signed-off-by: Junio C Hamano --- t/t0050-filesystem.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index 89282ccf7a..41df6bcf27 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -108,13 +108,17 @@ $test_case 'merge (case change)' ' ' -$test_case 'add (with different case)' ' + + +test_expect_failure 'add (with different case)' ' git reset --hard initial && rm camelcase && echo 1 >CamelCase && git add CamelCase && - test $(git ls-files | grep -i camelcase | wc -l) = 1 + camel=$(git ls-files | grep -i camelcase) && + test $(echo "$camel" | wc -l) = 1 && + test "z$(git cat-file blob :$camel)" = z1 ' From 6e57b431f2399964870680ffdd3325507111d3ee Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 28 Feb 2010 19:12:31 -0800 Subject: [PATCH 0652/3720] tests for "git add ignored-dir/file" without -f Signed-off-by: Junio C Hamano --- t/t2204-add-ignored.sh | 79 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 t/t2204-add-ignored.sh diff --git a/t/t2204-add-ignored.sh b/t/t2204-add-ignored.sh new file mode 100755 index 0000000000..24afdabab7 --- /dev/null +++ b/t/t2204-add-ignored.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +test_description='giving ignored paths to git add' + +. ./test-lib.sh + +test_expect_success setup ' + mkdir sub dir dir/sub && + echo sub >.gitignore && + echo ign >>.gitignore && + for p in . sub dir dir/sub + do + >"$p/ign" && + >"$p/file" || exit 1 + done +' + +for i in file dir/file dir 'd*' +do + test_expect_success "no complaints for unignored $i" ' + rm -f .git/index && + git add "$i" && + git ls-files "$i" >out && + test -s out + ' +done + +for i in ign dir/ign dir/sub dir/sub/*ign sub/file sub sub/* +do + test_expect_success "complaints for ignored $i" ' + rm -f .git/index && + test_must_fail git add "$i" 2>err && + git ls-files "$i" >out && + ! test -s out && + grep -e "Use -f if" err && + cat err + ' + + test_expect_success "complaints for ignored $i with unignored file" ' + rm -f .git/index && + test_must_fail git add "$i" file 2>err && + git ls-files "$i" >out && + ! test -s out && + grep -e "Use -f if" err && + cat err + ' +done + +for i in sub sub/* +do + test_expect_success "complaints for ignored $i in dir" ' + rm -f .git/index && + ( + cd dir && + test_must_fail git add "$i" 2>err && + git ls-files "$i" >out && + ! test -s out && + grep -e "Use -f if" err && + cat err + ) + ' +done + +for i in ign file +do + test_expect_success "complaints for ignored $i in sub" ' + rm -f .git/index && + ( + cd sub && + test_must_fail git add "$i" 2>err && + git ls-files "$i" >out && + ! test -s out && + grep -e "Use -f if" err && + cat err + ) + ' +done + +test_done From 13bb0ce6b77833c0b6a8377d0af7151ee3453a7b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 28 Feb 2010 23:33:46 -0800 Subject: [PATCH 0653/3720] builtin-add: fix exclude handling After we finish walking the working tree to find paths to add, the prune_directory() function checks the pathspecs to find typoes in them. When a given pathspec did not produce any match (either in the untracked files, or paths already in the index), there are two cases: - "git add no-such-file", i.e. the pathspec was misspelled; or - "git add ignored-pattern.o", i.e. the pathspec exactly matches but is ignored by the traversal. For the former, the function immediately errored out. The latter were queued in the dir structure and later used to give an error message with "use -f if you really mean it" advice. e96980e (builtin-add: simplify (and increase accuracy of) exclude handling, 2007-06-12) somehow lost the latter. This adds the logic back, but with a bit of twist, as it uses collect_ignored option that does half the necessary work during the traversal. Signed-off-by: Junio C Hamano --- builtin-add.c | 23 ++++++++++++++++++++--- dir.c | 10 ++++------ dir.h | 2 ++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/builtin-add.c b/builtin-add.c index cb6e5906fb..c24c1bfa25 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -63,9 +63,26 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p fill_pathspec_matches(pathspec, seen, specs); for (i = 0; i < specs; i++) { - if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i])) - die("pathspec '%s' did not match any files", - pathspec[i]); + const char *match; + if (seen[i]) + continue; + match = pathspec[i]; + if (!match[0]) + continue; + + /* Existing file? We must have ignored it */ + if (file_exists(match)) { + int len = strlen(match); + int i; + for (i = 0; i < dir->ignored_nr; i++) + if (dir->ignored[i]->len == len && + !memcmp(dir->ignored[i]->name, match, len)) + break; + if (dir->ignored_nr <= i) + dir_add_ignored(dir, match, strlen(match)); + continue; + } + die("pathspec '%s' did not match any files", match); } free(seen); } diff --git a/dir.c b/dir.c index 00d698d79f..11d8954829 100644 --- a/dir.c +++ b/dir.c @@ -413,13 +413,10 @@ static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathna return dir->entries[dir->nr++] = dir_entry_new(pathname, len); } -static struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len) +void dir_add_ignored(struct dir_struct *dir, const char *pathname, int len) { - if (!cache_name_is_other(pathname, len)) - return NULL; - ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc); - return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len); + dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len); } enum exist_status { @@ -638,7 +635,8 @@ static enum path_treatment treat_one_path(struct dir_struct *dir, { int exclude = excluded(dir, path, &dtype); if (exclude && (dir->flags & DIR_COLLECT_IGNORED) - && in_pathspec(path, *len, simplify)) + && in_pathspec(path, *len, simplify) + && cache_name_is_other(path, *len)) dir_add_ignored(dir, path, *len); /* diff --git a/dir.h b/dir.h index 320b6a2f38..9bc33379cb 100644 --- a/dir.h +++ b/dir.h @@ -96,4 +96,6 @@ extern int remove_dir_recursively(struct strbuf *path, int flag); /* tries to remove the path with empty directories along it, ignores ENOENT */ extern int remove_path(const char *path); +extern void dir_add_ignored(struct dir_struct *, const char *, int); + #endif From 11128eb9dacd05fc34912e39e16f5965dc9f47e2 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sat, 6 Mar 2010 21:34:45 +0100 Subject: [PATCH 0654/3720] cherry-pick: add a no-op --no-ff option to future proof scripts A --ff option to allow "git cherry-pick" to fast forward if possible was added in a previous patch, and this behavior may become the default one in the future. So to future proof scripts that may rely on the current behavior it is safer to add a --no-ff option to make sure that the current behavior will be used. Requested-by: Paolo Bonzini Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/git-cherry-pick.txt | 6 +++++- builtin-revert.c | 6 +++++- t/t3506-cherry-pick-ff.sh | 8 ++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index d71607a85d..dfc82432fc 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit SYNOPSIS -------- -'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] +'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--[no-]ff] DESCRIPTION ----------- @@ -75,6 +75,10 @@ effect to your index in a row. cherry-pick'ed commit, then a fast forward to this commit will be performed. +--no-ff:: + Does nothing right now, but in the future this may disallow + fast forward if it becomes the default behavior. + Author ------ Written by Junio C Hamano diff --git a/builtin-revert.c b/builtin-revert.c index 476f41e760..0651e34742 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -36,7 +36,7 @@ static const char * const cherry_pick_usage[] = { NULL }; -static int edit, no_replay, no_commit, mainline, signoff, allow_ff; +static int edit, no_replay, no_commit, mainline, signoff, allow_ff, no_ff; static enum { REVERT, CHERRY_PICK } action; static struct commit *commit; static const char *commit_name; @@ -63,11 +63,13 @@ static void parse_args(int argc, const char **argv) OPT_END(), OPT_END(), OPT_END(), + OPT_END(), }; if (action == CHERRY_PICK) { struct option cp_extra[] = { OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"), + OPT_BOOLEAN(0, "no-ff", &no_ff, "disallow fast forward"), OPT_END(), }; if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra)) @@ -297,6 +299,8 @@ static int revert_or_cherry_pick(int argc, const char **argv) die("cherry-pick --ff cannot be used with -x"); if (edit) die("cherry-pick --ff cannot be used with --edit"); + if (no_ff) + die("cherry-pick --ff cannot be used with --no-ff"); } if (read_cache() < 0) diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh index e17ae712b1..2d7e532892 100755 --- a/t/t3506-cherry-pick-ff.sh +++ b/t/t3506-cherry-pick-ff.sh @@ -35,6 +35,14 @@ test_expect_success 'cherry-pick not using --ff does not fast forwards' ' test "$(git rev-parse --verify HEAD)" != "$(git rev-parse --verify second)" ' +test_expect_success 'cherry-pick using --no-ff does not fast forwards' ' + git checkout master && + git reset --hard first && + test_tick && + git cherry-pick --no-ff second && + test "$(git rev-parse --verify HEAD)" != "$(git rev-parse --verify second)" +' + # # We setup the following graph: # From f1fe9d7ba43ef56dc875a8a6fb4d9903d58d2086 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sat, 6 Mar 2010 21:34:46 +0100 Subject: [PATCH 0655/3720] rebase -i: use new --ff cherry-pick option This simplifies rebase -i a little bit. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 3e4fd1456f..92d19f5903 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -222,8 +222,8 @@ do_with_author () { } pick_one () { - no_ff= - case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac + ff=--ff + case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1" test -d "$REWRITTEN" && pick_one_preserving_merges "$@" && return @@ -232,16 +232,7 @@ pick_one () { output git cherry-pick "$@" return fi - parent_sha1=$(git rev-parse --verify $sha1^) || - die "Could not get the parent of $sha1" - current_sha1=$(git rev-parse --verify HEAD) - if test -z "$no_ff" && test "$current_sha1" = "$parent_sha1" - then - output git reset --hard $sha1 - output warn Fast-forward to $(git rev-parse --short $sha1) - else - output git cherry-pick "$@" - fi + output git cherry-pick $ff "$@" } pick_one_preserving_merges () { From b38a696841b1f1a74b35e5cac7074f8077ff7d07 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Mar 2010 00:41:08 +0100 Subject: [PATCH 0656/3720] mingw: support fopen(/dev/null) Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e637209baf..d131092a6e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -225,7 +225,7 @@ FILE *mingw_fopen (const char *filename, const char *mode) basename((char*)filename)[0] == '.') hide = access(filename, F_OK); - file = fopen(filename, mode); + file = fopen(strcmp(filename, "/dev/null") ? filename : "NUL", mode); /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when From f34a7373a412158e6b3611176a136c43179fe024 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0657/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From 0c48e5ba6f79ff5a28a1aa2fa363e4cd39a6fc36 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0658/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From ef6aded56341fbb09c13c3ca96bd914c7a2509f6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0659/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 326fd3a1c2d2f40673637b30d61705b053abd138 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0660/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..2f1d076af7 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From dceac1e66c4335ed59fe68adaf0c89fe0caa51fd Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 2 Feb 2010 23:03:24 +0100 Subject: [PATCH 0661/3720] gitk: Add shortcut Ctrl-W for closing the active window To make the user experience between git gui and gitk more homogeneous, use Ctrl-W in gitk too for closing the active window. When closing the main window doquit is called for proper cleanup. Signed-off-by: Jens Lehmann --- gitk-git/gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index cdedaa7121..d0a51ef5d1 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2383,6 +2383,8 @@ proc makewindow {} { } bindall <$::BM> "canvscan mark %W %x %y" bindall "canvscan dragto %W %x %y" + bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} + bind . <$M1B-Key-w> doquit bindkey selfirstline bindkey sellastline bind . "selnextline -1" @@ -2815,6 +2817,7 @@ proc keys {} { [mc "Gitk key bindings:"] [mc "<%s-Q> Quit" $M1T] +[mc "<%s-W> Close window" $M1T] [mc " Move to first commit"] [mc " Move to last commit"] [mc ", p, i Move up one commit"] From 86058f6803510aface880d2e7690d45d2eb62b08 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 0662/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 4a034803db43183ad347092fcb6a34ce5dbac367 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 0663/3720] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index cdedaa7121..a22888c862 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9397,7 +9397,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 888ef1ec0c362a58a89b2427659351f315dae11c Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 0664/3720] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 87ad2b93f7..103d8d884d 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9401,11 +9401,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From 99a20add785ad40e729fe0f09f55901752354421 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 13 Mar 2010 23:24:00 -0800 Subject: [PATCH 0665/3720] Revert "Merge branch 'jc/maint-add-ignored-dir' into next" This reverts commit a51762e867e958f21e8f93c0ec6fb62f5dcc6739, reversing changes made to ba02883a06daff915156c021bd4860f199b20468. --- builtin/add.c | 24 ------------- dir.c | 10 +++--- dir.h | 2 -- t/t0050-filesystem.sh | 8 ++--- t/t2204-add-ignored.sh | 79 ------------------------------------------ 5 files changed, 8 insertions(+), 115 deletions(-) delete mode 100755 t/t2204-add-ignored.sh diff --git a/builtin/add.c b/builtin/add.c index 4499205698..87d2980313 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -149,30 +149,6 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int } dir->nr = dst - dir->entries; fill_pathspec_matches(pathspec, seen, specs); - - for (i = 0; i < specs; i++) { - const char *match; - if (seen[i]) - continue; - match = pathspec[i]; - if (!match[0]) - continue; - - /* Existing file? We must have ignored it */ - if (file_exists(match)) { - int len = strlen(match); - int i; - for (i = 0; i < dir->ignored_nr; i++) - if (dir->ignored[i]->len == len && - !memcmp(dir->ignored[i]->name, match, len)) - break; - if (dir->ignored_nr <= i) - dir_add_ignored(dir, match, strlen(match)); - continue; - } - die("pathspec '%s' did not match any files", match); - } - return seen; } diff --git a/dir.c b/dir.c index 2f05e7d39d..133c333df6 100644 --- a/dir.c +++ b/dir.c @@ -453,10 +453,13 @@ static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathna return dir->entries[dir->nr++] = dir_entry_new(pathname, len); } -void dir_add_ignored(struct dir_struct *dir, const char *pathname, int len) +static struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len) { + if (!cache_name_is_other(pathname, len)) + return NULL; + ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc); - dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len); + return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len); } enum exist_status { @@ -675,8 +678,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir, { int exclude = excluded(dir, path, &dtype); if (exclude && (dir->flags & DIR_COLLECT_IGNORED) - && in_pathspec(path, *len, simplify) - && cache_name_is_other(path, *len)) + && in_pathspec(path, *len, simplify)) dir_add_ignored(dir, path, *len); /* diff --git a/dir.h b/dir.h index 1f5ba94441..3bead5f0e2 100644 --- a/dir.h +++ b/dir.h @@ -100,6 +100,4 @@ extern int remove_dir_recursively(struct strbuf *path, int flag); /* tries to remove the path with empty directories along it, ignores ENOENT */ extern int remove_path(const char *path); -extern void dir_add_ignored(struct dir_struct *, const char *, int); - #endif diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index 41df6bcf27..89282ccf7a 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -108,17 +108,13 @@ $test_case 'merge (case change)' ' ' - - -test_expect_failure 'add (with different case)' ' +$test_case 'add (with different case)' ' git reset --hard initial && rm camelcase && echo 1 >CamelCase && git add CamelCase && - camel=$(git ls-files | grep -i camelcase) && - test $(echo "$camel" | wc -l) = 1 && - test "z$(git cat-file blob :$camel)" = z1 + test $(git ls-files | grep -i camelcase | wc -l) = 1 ' diff --git a/t/t2204-add-ignored.sh b/t/t2204-add-ignored.sh deleted file mode 100755 index 24afdabab7..0000000000 --- a/t/t2204-add-ignored.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh - -test_description='giving ignored paths to git add' - -. ./test-lib.sh - -test_expect_success setup ' - mkdir sub dir dir/sub && - echo sub >.gitignore && - echo ign >>.gitignore && - for p in . sub dir dir/sub - do - >"$p/ign" && - >"$p/file" || exit 1 - done -' - -for i in file dir/file dir 'd*' -do - test_expect_success "no complaints for unignored $i" ' - rm -f .git/index && - git add "$i" && - git ls-files "$i" >out && - test -s out - ' -done - -for i in ign dir/ign dir/sub dir/sub/*ign sub/file sub sub/* -do - test_expect_success "complaints for ignored $i" ' - rm -f .git/index && - test_must_fail git add "$i" 2>err && - git ls-files "$i" >out && - ! test -s out && - grep -e "Use -f if" err && - cat err - ' - - test_expect_success "complaints for ignored $i with unignored file" ' - rm -f .git/index && - test_must_fail git add "$i" file 2>err && - git ls-files "$i" >out && - ! test -s out && - grep -e "Use -f if" err && - cat err - ' -done - -for i in sub sub/* -do - test_expect_success "complaints for ignored $i in dir" ' - rm -f .git/index && - ( - cd dir && - test_must_fail git add "$i" 2>err && - git ls-files "$i" >out && - ! test -s out && - grep -e "Use -f if" err && - cat err - ) - ' -done - -for i in ign file -do - test_expect_success "complaints for ignored $i in sub" ' - rm -f .git/index && - ( - cd sub && - test_must_fail git add "$i" 2>err && - git ls-files "$i" >out && - ! test -s out && - grep -e "Use -f if" err && - cat err - ) - ' -done - -test_done From ccc538e353bc7d137b1fe59b19f5a7ae85aaa312 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 0666/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 31 ++++++++++++++++++++++++------- compat/mingw.h | 3 ++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0df1a3d5ea..9c10a4cb79 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -334,8 +334,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) * We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -357,11 +360,16 @@ static int do_lstat(const char *file_name, struct stat *buf) if (handle != INVALID_HANDLE_VALUE) { if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { - char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - buf->st_mode = S_IREAD | S_IFLNK; + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) buf->st_mode |= S_IWRITE; - buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); } FindClose(handle); } @@ -378,12 +386,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* @@ -403,7 +411,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 4650d8a882..ff5477b553 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -222,10 +222,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From db2af245ebab3f6a52abc3efb0ec76bd543b59f3 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 0667/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9c10a4cb79..fc53b79284 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1548,6 +1548,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1557,9 +1558,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 5cf938f51e7331e269078eff85f3460c3926681e Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 0668/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 5386504790..8cb12222ca 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -291,4 +291,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index c1951bb021..8132d24b4d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -773,6 +773,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 9d2ad68fc674c54698248d7834151e250fd70f64 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 0669/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index fc53b79284..9af3c60814 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -134,7 +134,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 65c91d45f588dcf86524b98587ff988308f57c1d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Mar 2010 11:45:10 -0700 Subject: [PATCH 0670/3720] Revert "cherry-pick: add a no-op --no-ff option to future proof scripts" This reverts commit 11128eb9dacd05fc34912e39e16f5965dc9f47e2, as "cherry-pick --ff" will never be the default. --- Documentation/git-cherry-pick.txt | 6 +----- builtin/revert.c | 6 +----- t/t3506-cherry-pick-ff.sh | 8 -------- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index dfc82432fc..d71607a85d 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit SYNOPSIS -------- -'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--[no-]ff] +'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] DESCRIPTION ----------- @@ -75,10 +75,6 @@ effect to your index in a row. cherry-pick'ed commit, then a fast forward to this commit will be performed. ---no-ff:: - Does nothing right now, but in the future this may disallow - fast forward if it becomes the default behavior. - Author ------ Written by Junio C Hamano diff --git a/builtin/revert.c b/builtin/revert.c index 0651e34742..476f41e760 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -36,7 +36,7 @@ static const char * const cherry_pick_usage[] = { NULL }; -static int edit, no_replay, no_commit, mainline, signoff, allow_ff, no_ff; +static int edit, no_replay, no_commit, mainline, signoff, allow_ff; static enum { REVERT, CHERRY_PICK } action; static struct commit *commit; static const char *commit_name; @@ -63,13 +63,11 @@ static void parse_args(int argc, const char **argv) OPT_END(), OPT_END(), OPT_END(), - OPT_END(), }; if (action == CHERRY_PICK) { struct option cp_extra[] = { OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"), - OPT_BOOLEAN(0, "no-ff", &no_ff, "disallow fast forward"), OPT_END(), }; if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra)) @@ -299,8 +297,6 @@ static int revert_or_cherry_pick(int argc, const char **argv) die("cherry-pick --ff cannot be used with -x"); if (edit) die("cherry-pick --ff cannot be used with --edit"); - if (no_ff) - die("cherry-pick --ff cannot be used with --no-ff"); } if (read_cache() < 0) diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh index 2d7e532892..e17ae712b1 100755 --- a/t/t3506-cherry-pick-ff.sh +++ b/t/t3506-cherry-pick-ff.sh @@ -35,14 +35,6 @@ test_expect_success 'cherry-pick not using --ff does not fast forwards' ' test "$(git rev-parse --verify HEAD)" != "$(git rev-parse --verify second)" ' -test_expect_success 'cherry-pick using --no-ff does not fast forwards' ' - git checkout master && - git reset --hard first && - test_tick && - git cherry-pick --no-ff second && - test "$(git rev-parse --verify HEAD)" != "$(git rev-parse --verify second)" -' - # # We setup the following graph: # From 5c1e99faf4cbe2c171fcad72812d4ff8ca48b47f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 0671/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9af3c60814..6e04c55ce4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -364,7 +364,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From d00d6559bb551fe6e1cd6543804f6a36cf2f6475 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 0672/3720] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index 9d30ddb28d..4e29bbee70 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -582,7 +582,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1001,28 +1000,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From 8e47f498ab4117d7f256f93d8d437dbbd4a999bb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 0673/3720] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index 4e29bbee70..ec397cdb1e 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include "thread-utils.h" @@ -548,6 +549,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -773,9 +799,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -859,6 +887,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -934,6 +964,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -999,6 +1043,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1021,6 +1088,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 6bae30545b..6db05e0df8 100644 --- a/git.c +++ b/git.c @@ -320,7 +320,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep, RUN_SETUP }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From c0d50e35f612535c16638b932287c91ed39f929a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 0674/3720] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index ec397cdb1e..ba5452642f 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -799,7 +799,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -887,8 +887,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -965,16 +966,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From 52b98a7d2f12b5d0dd076221d40f8fa93598e11a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 4 Apr 2010 15:40:06 -0700 Subject: [PATCH 0675/3720] write-index: check and warn when worktree crosses a filesystem boundary As we are stopping the discovery for the repository directory at filesystem boundaries by default, you might find yourself in a situation like this: (1) You have a tarball of some sort; you extract it $there; $ mkdir $there && cd $there $ tar xf /var/tmp/tarball.tar (2) You notice that the filesystem lacks enough free space, and move some part (say "images/") to a separate filesystem, and bind-mount; $ mv images $another/. && rm -fr images && mkdir images $ mount --bind $another/images images (3) You add everything to start the project; $ git init && git add . Up to this point it would work just fine, as you are at the top of the working tree and there is no need for repository discovery. (4) Go down to a subdirectory and start futzing; $ cd images && gimp naughty.jpg && git add -u This will break as the repository discovery will not go up outside of the "images" directory. Help users by making "git add" notice at the step (3) above that the working tree is spread across multiple filesystems and warn. Signed-off-by: Junio C Hamano --- read-cache.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/read-cache.c b/read-cache.c index f1f789b7b8..e381ea52a3 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1550,6 +1550,8 @@ int write_index(struct index_state *istate, int newfd) struct cache_entry **cache = istate->cache; int entries = istate->cache_nr; struct stat st; + int first_valid_ent = -1; + int more_than_one_dev; for (i = removed = extended = 0; i < entries; i++) { if (cache[i]->ce_flags & CE_REMOVE) @@ -1572,6 +1574,7 @@ int write_index(struct index_state *istate, int newfd) if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) return -1; + more_than_one_dev = 0; for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; if (ce->ce_flags & CE_REMOVE) @@ -1580,8 +1583,19 @@ int write_index(struct index_state *istate, int newfd) ce_smudge_racily_clean_entry(ce); if (ce_write_entry(&c, newfd, ce) < 0) return -1; + if (ce_uptodate(ce)) { + if (first_valid_ent < 0) + first_valid_ent = i; + else if (ce->ce_dev != cache[first_valid_ent]->ce_dev) + more_than_one_dev = 1; + } } + if (more_than_one_dev && + !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0)) + warning("working tree spans across filesystems but " + "GIT_DISCOVERY_ACROSS_FILESYSTEM is not set."); + /* Write extension data here */ if (istate->cache_tree) { struct strbuf sb = STRBUF_INIT; From cf4df60f7a12f22ea81385f176907320b422fc2e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 18:40:30 +0200 Subject: [PATCH 0676/3720] git am: accept patches downloaded from GMane GMane has this wonderful feature that you can download the raw mails, but the mails do not fully conform to the mbox format, as they do not start with a "From ..." line. But they start with another tell tale we can easily detect. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..11c35afb9c 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "*) + "From "* | "From: "* | "Path:news.gmane.org"*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 10b6d8a4140dc43b0a16b596288539d56fe2836b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0677/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 515851c31e..07f0f08ade 100644 --- a/Makefile +++ b/Makefile @@ -1851,6 +1851,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1858,6 +1859,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From f2131a6dda7e76f1bb31ab7ec135e5f82826f16e Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0678/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3347362632..a75094b257 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 52522d24e4110cd2d7e62cb5c6266e59a2795e49 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0679/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index a75094b257..2082e3d2bd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From d4747054af8e5142583a7caa780a14f188a852ab Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0680/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 626b19ac93..2df16315d6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index edc40ff574..76e0fa0525 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 0f4263c09a..52c35301ac 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 30716903f5..34baee3115 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,23 +172,50 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2082e3d2bd..e090faa69e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -276,6 +273,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 64e41bea22..535eed8c75 100644 --- a/config.c +++ b/config.c @@ -536,6 +536,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index b56c297b04..a4769334b1 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -490,4 +490,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From d6ffa16437c0d0305aaa98d300742897e09f9629 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0681/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 34baee3115..921ca7c61f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From fd198cb64c46f54d43e219abd759384881243aa2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Jan 2010 18:16:25 +0100 Subject: [PATCH 0682/3720] Revert "git am: accept patches downloaded from GMane" This reverts commit 127aa63757870526b106c045310a3b6c4cee0324. As pointed out by Junio, this patch was obsoleted by 0fcb2ca. --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 11c35afb9c..1056075545 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "* | "Path:news.gmane.org"*) + "From "* | "From: "*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 2b30504bf120336d797b8593a7605c4de55e4774 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0683/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 125a0a151c6bebb64d0e56709ef137226bf5dff6 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0684/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index f11f98c3ce..90541a39c6 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index c582964b0d..97f3e7f50e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -782,6 +782,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 1cce13c1fb70cd99b9e27f4e10ea9b0e954a91aa Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0685/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From a8a00c3393dff53128ebf83c063efaefcb6502d2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0686/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 921ca7c61f..095294ee80 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index e090faa69e..ff9611bf74 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From e17d791256e10ecd15f804da51774e92fa755fea Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0687/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 095294ee80..25479604fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1224,7 +1240,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From eeb39261e100701aa310a51ab0753075b42110c5 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0688/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 83338e1cba1eb0bb170441a7e2447a60337cd61f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0689/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 5950d13b824b4900e52f5ceccf235e89ef20c63e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0690/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From b7bec05fcadab1dc831906e297d5c88c8c0bf193 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0691/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From 661c66869951ac3512795e033c651526100ba769 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0692/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From bee55df28b9ed5621df9ab36f991afbde89b6988 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0693/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 7aeb2e85ea43ff040d9b11d3ee85412e3d44aeac Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0694/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 1095338b07cf721f68416b7f8abb81a126a32892 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0695/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 25479604fa..78ad8f76fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1281,6 +1334,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From cc0ee235d666431a65f61902381cf2a44d055307 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0696/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 78ad8f76fb..6ecad87476 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index ff9611bf74..cdd119c473 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 0648946884bbdd0e21e70456fb3fa8fee59e2dd7 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0697/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 59a159417e07174bc4189849a8482e587624ba03 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 2 Feb 2010 23:03:24 +0100 Subject: [PATCH 0698/3720] gitk: Add shortcut Ctrl-W for closing the active window To make the user experience between git gui and gitk more homogeneous, use Ctrl-W in gitk too for closing the active window. When closing the main window doquit is called for proper cleanup. Signed-off-by: Jens Lehmann --- gitk-git/gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1f36a3e815..50773a3d9d 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2383,6 +2383,8 @@ proc makewindow {} { } bindall <$::BM> "canvscan mark %W %x %y" bindall "canvscan dragto %W %x %y" + bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} + bind . <$M1B-Key-w> doquit bindkey selfirstline bindkey sellastline bind . "selnextline -1" @@ -2814,6 +2816,7 @@ proc keys {} { [mc "Gitk key bindings:"] [mc "<%s-Q> Quit" $M1T] +[mc "<%s-W> Close window" $M1T] [mc " Move to first commit"] [mc " Move to last commit"] [mc ", p, i Move up one commit"] From c468c93eec068e4230bdd6b0d8bff49941c102e8 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 0699/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 56a4a1237f8892d1d36d4c45e4b14683dfd2a8c4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 0700/3720] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 50773a3d9d..2815f04328 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9399,7 +9399,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 5756bfec1fae7337142200d4bf7bdcc107064f40 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 0701/3720] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2815f04328..793c4373b4 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9400,11 +9400,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From aa2a0ce5568199e3d212b25280ffb7e8cf9fdf37 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 0702/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6ecad87476..4348b60296 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -343,8 +343,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -360,6 +363,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -371,12 +394,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -395,7 +418,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index cdd119c473..756f3ab062 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -227,10 +227,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From fa90864c14d9de28c201c08000ab71073bcaf640 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 0703/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4348b60296..cc47d6834a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1566,6 +1566,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1575,9 +1576,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 3a5cb16bc85891f1a1c3c10ca00d378e5ed4ced6 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 0704/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 675773479a..5bacf2278c 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -310,4 +310,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 97f3e7f50e..e2379b8ad2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -777,6 +777,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 93c41c10cd006b89141c8d812efb7c15d86f7835 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 0705/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index cc47d6834a..bbae2be946 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 5bbaae2a6f79d828d18b4ddab55ad17ffff6bba8 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 0706/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index bbae2be946..7ec615c5ac 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -373,7 +373,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From bd21d65fd30ec1d47248e4b5ff82c101311cd31c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 0707/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..4db4f42516 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,7 +444,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 4dc7d3b9f940463810d66dcddd9ccee7dc8c2e99 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 0708/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -154,6 +158,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -172,6 +180,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -219,6 +231,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a9df7ff7bd..e439b0f8ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -607,6 +607,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -623,6 +627,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -649,8 +657,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -665,6 +681,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -700,6 +720,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 65b2c099be2ce7ac71f416c4d2e28752229e0bf4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 19:13:36 +0200 Subject: [PATCH 0709/3720] Fix rebase of grep-O grep no longer wants setup to be run already. Signed-off-by: Johannes Schindelin --- git.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git.c b/git.c index 6db05e0df8..19b45f29e1 100644 --- a/git.c +++ b/git.c @@ -320,7 +320,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, RUN_SETUP }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 0fff3fe82239a459f71a3af56994feafc35ed0e0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 16:47:51 +0200 Subject: [PATCH 0710/3720] Replace obsolete 'diff' call with 'test_cmp' Signed-off-by: Johannes Schindelin --- t/t7002-grep.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index e249c3ed41..8a6322765c 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -60,7 +60,7 @@ do echo ${HC}file:5:foo_mmap bar mmap baz } >expected && git grep -n -w -e mmap $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (w)" ' @@ -74,7 +74,7 @@ do echo ${HC}x:1:x x xx x } >expected && git grep -n -w -e "x xx* x" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-1)" ' @@ -82,7 +82,7 @@ do echo ${HC}y:1:y yy } >expected && git grep -n -w -e "^y" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-2)" ' @@ -93,7 +93,7 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' @@ -105,14 +105,14 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' test_expect_success "grep $L (t-1)" ' echo "${HC}t/t:1:test" >expected && git grep -n -e test $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-2)" ' @@ -121,7 +121,7 @@ do cd t && git grep -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-3)" ' @@ -130,7 +130,7 @@ do cd t && git grep --full-name -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -c $L (no /dev/null)" ' From 3bb030015f2f0f516fcb2c0deab34bcfaf3d39ba Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 0711/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 56 +++++++++++++++++++++++++++++++++++++++- t/t5516-fetch-push.sh | 36 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 2df16315d6..dcf5e87fcc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1538,6 +1538,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 0559fcc871..f35070358f 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,6 +17,8 @@ enum deny_action { DENY_IGNORE, DENY_WARN, DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -78,7 +80,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2de98e6561..59caa61a52 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -710,4 +710,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 96cfcbb2278a36ab3aa09389a32466a8ca8993fd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 18:40:30 +0200 Subject: [PATCH 0712/3720] git am: accept patches downloaded from GMane GMane has this wonderful feature that you can download the raw mails, but the mails do not fully conform to the mbox format, as they do not start with a "From ..." line. But they start with another tell tale we can easily detect. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..11c35afb9c 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "*) + "From "* | "From: "* | "Path:news.gmane.org"*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 3998051fa34064f61e7387dfbaaa10563ab8dc77 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0713/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index f0fe351df9..adcca6c97b 100644 --- a/Makefile +++ b/Makefile @@ -1853,6 +1853,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1860,6 +1861,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 11bcc68dc9565eb9a7b6b1e81eee9f649283fd12 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0714/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3347362632..a75094b257 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 7574d99881479f8d3659847d52703da7b2be9413 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0715/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index a75094b257..2082e3d2bd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 891b3d11b1dde30af7285705432ab49d38af48f1 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0716/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 626b19ac93..2df16315d6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index edc40ff574..76e0fa0525 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 303c10771b..8ae215c6ef 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 30716903f5..34baee3115 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,23 +172,50 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2082e3d2bd..e090faa69e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -276,6 +273,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 9b6b1df212..67a82f055e 100644 --- a/config.c +++ b/config.c @@ -579,6 +579,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index b56c297b04..a4769334b1 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -490,4 +490,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 38ab60d7e5c73d4c2cd1fcdd177ffa5043ccf3ea Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0717/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 34baee3115..921ca7c61f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 41bc9dba9fc2e30b47384ebb1ce1f568ec5b4a0a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Jan 2010 18:16:25 +0100 Subject: [PATCH 0718/3720] Revert "git am: accept patches downloaded from GMane" This reverts commit 127aa63757870526b106c045310a3b6c4cee0324. As pointed out by Junio, this patch was obsoleted by 0fcb2ca. --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 11c35afb9c..1056075545 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "* | "Path:news.gmane.org"*) + "From "* | "From: "*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 27156a29cc468692a15b4b6500e365ee839eb3f8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0719/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 67bb5597ea631d88b0e8eff4a0d3275a24f51d75 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0720/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64f05080b6..ae6bf7c219 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index c582964b0d..97f3e7f50e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -782,6 +782,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 26c00eab4de541c9dba9bf883402ed1f00bd7e68 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0721/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 87635ed04500887db49e4ce65f0b8df2c48c8210 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0722/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 921ca7c61f..095294ee80 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index e090faa69e..ff9611bf74 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 1de9be03d51ec386e38e3ef870dc16a18f67d7e5 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0723/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 095294ee80..25479604fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1224,7 +1240,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From fae5dc25a76afb61da854a1c3594166533c7576a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0724/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 2ec79df99047bc5cd66ca23b624aa23de1ee49c7 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0725/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From f0849bf8094b58193f5f0e835f158bcc8c24e328 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0726/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From 1c73b79894b2ae7e461ee0ae548d70e37e10e898 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0727/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From 4e3c3a570d3eb8ac29b50af376b245534d1e8120 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0728/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From ea928bad8604b14071aa509fdfe17facea791ac2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0729/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 1de940e3997226c5e096644bd2fd92617255ac3e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0730/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 9da0cb5c86d833dcfda9a88e3c8cdaa58393ea92 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0731/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 25479604fa..78ad8f76fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1281,6 +1334,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 9b275e71be24ae9b0ed5c4b1a05cb94f2e9e350b Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0732/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 78ad8f76fb..6ecad87476 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index ff9611bf74..cdd119c473 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 3876a4604add8888959320580d7e8435d3ee2860 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0733/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 62cd93c1dfe0c43f5ff76ae4bf47b3e6ae1ce3dc Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 2 Feb 2010 23:03:24 +0100 Subject: [PATCH 0734/3720] gitk: Add shortcut Ctrl-W for closing the active window To make the user experience between git gui and gitk more homogeneous, use Ctrl-W in gitk too for closing the active window. When closing the main window doquit is called for proper cleanup. Signed-off-by: Jens Lehmann --- gitk-git/gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1f36a3e815..50773a3d9d 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2383,6 +2383,8 @@ proc makewindow {} { } bindall <$::BM> "canvscan mark %W %x %y" bindall "canvscan dragto %W %x %y" + bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} + bind . <$M1B-Key-w> doquit bindkey selfirstline bindkey sellastline bind . "selnextline -1" @@ -2814,6 +2816,7 @@ proc keys {} { [mc "Gitk key bindings:"] [mc "<%s-Q> Quit" $M1T] +[mc "<%s-W> Close window" $M1T] [mc " Move to first commit"] [mc " Move to last commit"] [mc ", p, i Move up one commit"] From 493461349ded3479168ba99111615c9ec62716fc Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 0735/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 3b4f6cbfce4be76dd7f3310e8b74933d178988e5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 0736/3720] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 50773a3d9d..2815f04328 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9399,7 +9399,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From faeb863a7f18ad4e7f671c68c637467169a497cc Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 0737/3720] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2815f04328..793c4373b4 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9400,11 +9400,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From 62f864990a57a8868e9ce51a6866eb30b685797b Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 0738/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6ecad87476..4348b60296 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -343,8 +343,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -360,6 +363,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -371,12 +394,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -395,7 +418,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index cdd119c473..756f3ab062 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -227,10 +227,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 85e55a6565259e249afcc31cbded86236d80d681 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 0739/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4348b60296..cc47d6834a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1566,6 +1566,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1575,9 +1576,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From fd73c0b9bcb571fda706a47ac26636019b8f5161 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 0740/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 675773479a..5bacf2278c 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -310,4 +310,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 97f3e7f50e..e2379b8ad2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -777,6 +777,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From acc5880a61d720e9b757561314eef510bf4af45a Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 0741/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index cc47d6834a..bbae2be946 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From c8a1530575b76c6e444c683ef77b40fa005c6942 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 0742/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index bbae2be946..7ec615c5ac 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -373,7 +373,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 78d757687cab45251536d2daa3a8b5cae40e9508 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 0743/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..4db4f42516 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,7 +444,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From c5fc0e52b417af5499621801c4880c060d763d6a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 0744/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -154,6 +158,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -172,6 +180,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -219,6 +231,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a9df7ff7bd..e439b0f8ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -607,6 +607,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -623,6 +627,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -649,8 +657,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -665,6 +681,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -700,6 +720,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From f46fcc176a246cde86587b42752c4098ebb1c109 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 0745/3720] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index 8e928e2170..b2ac407ea8 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -590,7 +590,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1012,28 +1011,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From e1cf4f7b8bc8490a345bb0cf7c3e93025b414d72 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 0746/3720] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index b2ac407ea8..d85cb3f867 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include "thread-utils.h" @@ -556,6 +557,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -781,9 +807,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -867,6 +895,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -942,6 +972,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -1010,6 +1054,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1032,6 +1099,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 99f036302a..265fa09d8d 100644 --- a/git.c +++ b/git.c @@ -329,7 +329,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 5bf7ce7bc9bc67f8257f9581824ea5e5f6d73b60 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 0747/3720] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index d85cb3f867..4b1c5fc879 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -807,7 +807,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -895,8 +895,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -973,16 +974,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From ac5636e11e99dc0406fe455b88da921d10a68dbf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 16:47:51 +0200 Subject: [PATCH 0748/3720] Replace obsolete 'diff' call with 'test_cmp' Signed-off-by: Johannes Schindelin --- t/t7002-grep.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index e249c3ed41..8a6322765c 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -60,7 +60,7 @@ do echo ${HC}file:5:foo_mmap bar mmap baz } >expected && git grep -n -w -e mmap $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (w)" ' @@ -74,7 +74,7 @@ do echo ${HC}x:1:x x xx x } >expected && git grep -n -w -e "x xx* x" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-1)" ' @@ -82,7 +82,7 @@ do echo ${HC}y:1:y yy } >expected && git grep -n -w -e "^y" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-2)" ' @@ -93,7 +93,7 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' @@ -105,14 +105,14 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' test_expect_success "grep $L (t-1)" ' echo "${HC}t/t:1:test" >expected && git grep -n -e test $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-2)" ' @@ -121,7 +121,7 @@ do cd t && git grep -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-3)" ' @@ -130,7 +130,7 @@ do cd t && git grep --full-name -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -c $L (no /dev/null)" ' From 8a0f36e7280394c71d7821c1c24b4ab1febe9d44 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 0749/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 56 +++++++++++++++++++++++++++++++++++++++- t/t5516-fetch-push.sh | 36 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 2df16315d6..dcf5e87fcc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1538,6 +1538,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 0559fcc871..f35070358f 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,6 +17,8 @@ enum deny_action { DENY_IGNORE, DENY_WARN, DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -78,7 +80,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2de98e6561..59caa61a52 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -710,4 +710,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 9c63503c926ca1135e6fa89041e3b47fab829d77 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 18:40:30 +0200 Subject: [PATCH 0750/3720] git am: accept patches downloaded from GMane GMane has this wonderful feature that you can download the raw mails, but the mails do not fully conform to the mbox format, as they do not start with a "From ..." line. But they start with another tell tale we can easily detect. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..11c35afb9c 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "*) + "From "* | "From: "* | "Path:news.gmane.org"*) patch_format=mbox ;; '# This series applies on GIT commit'*) From c99542f51b5a60e5bc33a28cbeb948237b90d8d6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0751/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 87c90d6b80..1bb06bb8dc 100644 --- a/Makefile +++ b/Makefile @@ -1848,6 +1848,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1855,6 +1856,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 2ee859df0b8ef170d847af8651864d5248a4088d Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0752/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3347362632..a75094b257 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 1cc3c02fdcc9a28dab23809503f2ec97486e7841 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0753/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index a75094b257..2082e3d2bd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 0a4d61c121f8a3e82ac9e8260f30c05b58aa78f4 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0754/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 626b19ac93..2df16315d6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index edc40ff574..76e0fa0525 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 303c10771b..8ae215c6ef 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 30716903f5..34baee3115 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,23 +172,50 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2082e3d2bd..e090faa69e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -276,6 +273,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 9b6b1df212..67a82f055e 100644 --- a/config.c +++ b/config.c @@ -579,6 +579,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 4ee8f86f7a..7b2902f9cb 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -492,4 +492,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From aa86b307a60e2a3f7677d99f00700159b742e7f7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0755/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 34baee3115..921ca7c61f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From a4b68625479e5697d4e3f85bf23441ed7f00c152 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Jan 2010 18:16:25 +0100 Subject: [PATCH 0756/3720] Revert "git am: accept patches downloaded from GMane" This reverts commit 127aa63757870526b106c045310a3b6c4cee0324. As pointed out by Junio, this patch was obsoleted by 0fcb2ca. --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 11c35afb9c..1056075545 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "* | "Path:news.gmane.org"*) + "From "* | "From: "*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 98bd4ad4970eceb29a36af3fa75741aaaccaa1eb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0757/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 92d03c49d0f75fa04c218a40f3e23afff42a6b6a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0758/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64f05080b6..ae6bf7c219 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index c582964b0d..97f3e7f50e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -782,6 +782,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 6192be5ce619dfaa70875ade9f13c262de0d9264 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0759/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From a92d8e3484111d2a039d63f97d4df048c7e40c52 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0760/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 921ca7c61f..095294ee80 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index e090faa69e..ff9611bf74 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 88d1dbe6969ca038cd4551aa390985bfdf1b00ef Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0761/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 095294ee80..25479604fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1224,7 +1240,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 4fd6984e82ebcbb4ef4a4913004ee7effe25cc91 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0762/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 14bd66933609f312211fe89c6252fdc078e794ff Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0763/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 19c1cd04e4985e877760fc603432d072427efec9 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0764/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From a11a60a4f2d36a8b6cdefa614c2ac7f7c000dc06 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0765/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From a195394b832a2ea1f5ff142da3646f30cc3692df Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0766/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From 435584e2a4fbfc7da74349049f92a1d2e78f97ef Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0767/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 1a3910eb8c2aeb619580cf44b24733caac624871 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0768/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From a2b220086ba1f27b42394fdf6e72c5105d568d74 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0769/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 25479604fa..78ad8f76fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1281,6 +1334,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 2defae3462cfec17e2d5e51acdb1aa643acb4318 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0770/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 78ad8f76fb..6ecad87476 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index ff9611bf74..cdd119c473 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 8fa3c5f743c6946ffd4902f133cebbd86271738d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0771/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From e7eaa7114a99a914152114dd1adf870c6ca59a5d Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 2 Feb 2010 23:03:24 +0100 Subject: [PATCH 0772/3720] gitk: Add shortcut Ctrl-W for closing the active window To make the user experience between git gui and gitk more homogeneous, use Ctrl-W in gitk too for closing the active window. When closing the main window doquit is called for proper cleanup. Signed-off-by: Jens Lehmann --- gitk-git/gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1f36a3e815..50773a3d9d 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2383,6 +2383,8 @@ proc makewindow {} { } bindall <$::BM> "canvscan mark %W %x %y" bindall "canvscan dragto %W %x %y" + bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} + bind . <$M1B-Key-w> doquit bindkey selfirstline bindkey sellastline bind . "selnextline -1" @@ -2814,6 +2816,7 @@ proc keys {} { [mc "Gitk key bindings:"] [mc "<%s-Q> Quit" $M1T] +[mc "<%s-W> Close window" $M1T] [mc " Move to first commit"] [mc " Move to last commit"] [mc ", p, i Move up one commit"] From 6f75a58a47a75d4ef5029128e031547c71e202bc Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 0773/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 38cda0b0decd135fea7fcfc7fce75ab62e819c09 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 0774/3720] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 50773a3d9d..2815f04328 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9399,7 +9399,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From c57b92c1a1733e42d8497156db5596620c3ea7ca Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 0775/3720] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2815f04328..793c4373b4 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9400,11 +9400,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From 3a8fc9256d6fe6ed824c39e3b475b87dac9dc0fe Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 0776/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6ecad87476..4348b60296 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -343,8 +343,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -360,6 +363,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -371,12 +394,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -395,7 +418,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index cdd119c473..756f3ab062 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -227,10 +227,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From f67e4f300f3b15e0b9f6f2e75c31804bf189b062 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 0777/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4348b60296..cc47d6834a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1566,6 +1566,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1575,9 +1576,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 4eb7315e3566083cd92ab12adb611034c93d207c Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 0778/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 675773479a..5bacf2278c 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -310,4 +310,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 97f3e7f50e..e2379b8ad2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -777,6 +777,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 6e5ac68edf823e6441fbc227a20431d1976e6514 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 0779/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index cc47d6834a..bbae2be946 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From f971b944805779ff503093314b80e7cad9525d9f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 0780/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index bbae2be946..7ec615c5ac 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -373,7 +373,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 756a719c586c875980d321f96d3604ef1c8c0a55 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 0781/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..4db4f42516 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,7 +444,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From d3c402ff43caf5b90895040cce2abb12e8012e23 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 0782/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -154,6 +158,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -172,6 +180,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -219,6 +231,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a9df7ff7bd..e439b0f8ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -607,6 +607,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -623,6 +627,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -649,8 +657,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -665,6 +681,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -700,6 +720,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From e1a0ad012be06b3b1ae7a22b541de6a4bc991fae Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 0783/3720] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index b194ea3cea..a35ef71c27 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -590,7 +590,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1012,28 +1011,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From 6a5eac6a3150eb6bd650ea1eda0c24d273660ccc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 0784/3720] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index a35ef71c27..d0af900ded 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include @@ -556,6 +557,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -781,9 +807,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -867,6 +895,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -942,6 +972,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -1010,6 +1054,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1032,6 +1099,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 99f036302a..265fa09d8d 100644 --- a/git.c +++ b/git.c @@ -329,7 +329,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 78577c6a9f50761f3d08d654f72cb2ebdd953d99 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 0785/3720] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index d0af900ded..c87db91cf4 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -807,7 +807,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -895,8 +895,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -973,16 +974,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From 66eac8a91925744e19176f692c18daef47fdffd0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 16:47:51 +0200 Subject: [PATCH 0786/3720] Replace obsolete 'diff' call with 'test_cmp' Signed-off-by: Johannes Schindelin --- t/t7002-grep.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index e249c3ed41..8a6322765c 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -60,7 +60,7 @@ do echo ${HC}file:5:foo_mmap bar mmap baz } >expected && git grep -n -w -e mmap $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (w)" ' @@ -74,7 +74,7 @@ do echo ${HC}x:1:x x xx x } >expected && git grep -n -w -e "x xx* x" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-1)" ' @@ -82,7 +82,7 @@ do echo ${HC}y:1:y yy } >expected && git grep -n -w -e "^y" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-2)" ' @@ -93,7 +93,7 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' @@ -105,14 +105,14 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' test_expect_success "grep $L (t-1)" ' echo "${HC}t/t:1:test" >expected && git grep -n -e test $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-2)" ' @@ -121,7 +121,7 @@ do cd t && git grep -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-3)" ' @@ -130,7 +130,7 @@ do cd t && git grep --full-name -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -c $L (no /dev/null)" ' From b7955ea279cc8cac06de2be84d64a20b7d2a7ea9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 0787/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 56 +++++++++++++++++++++++++++++++++++++++- t/t5516-fetch-push.sh | 36 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 2df16315d6..dcf5e87fcc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1538,6 +1538,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 0559fcc871..f35070358f 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,6 +17,8 @@ enum deny_action { DENY_IGNORE, DENY_WARN, DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -78,7 +80,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2de98e6561..59caa61a52 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -710,4 +710,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From ee59bcd37dec47d313d99e245f72d707cbde9aee Mon Sep 17 00:00:00 2001 From: Ian McLean Date: Mon, 1 Mar 2010 14:58:45 -0500 Subject: [PATCH 0788/3720] Fix for issue 365: "Out of memory? mmap failed" The git_mmap implementation was broken for file sizes that wouldn't fit into a size_t (32 bits). Changed 'len' to be stored in an off_t (64 bit) variable, and moved the xsize_t cast to only occur when an attempt is made to map past the end-of-file. --- compat/win32mmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compat/win32mmap.c b/compat/win32mmap.c index 1c5a14922f..b58aa69fa0 100644 --- a/compat/win32mmap.c +++ b/compat/win32mmap.c @@ -4,19 +4,19 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of { HANDLE hmap; void *temp; - size_t len; + off_t len; struct stat st; uint64_t o = offset; uint32_t l = o & 0xFFFFFFFF; uint32_t h = (o >> 32) & 0xFFFFFFFF; if (!fstat(fd, &st)) - len = xsize_t(st.st_size); + len = st.st_size; else die("mmap: could not determine filesize"); if ((length + offset) > len) - length = len - offset; + length = xsize_t(len - offset); if (!(flags & MAP_PRIVATE)) die("Invalid usage of mmap when built with USE_WIN32_MMAP"); From f6a2f432a248f6b65cdb43a29905716fd3365ebc Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:15:40 -0400 Subject: [PATCH 0789/3720] start_command: close cmd->err descriptor when fork/spawn fails Fix the problem where the cmd->err passed into start_command wasn't being properly closed when certain types of errors occurr. (Compare the affected code with the clean shutdown code later in the function.) On Windows, this problem would be triggered if mingw_spawnvpe() failed, which would happen if the command to be executed was malformed (e.g. a text file that didn't start with a #! line). If cmd->err was a pipe, the failure to close it could result in a hang while the other side was waiting (forever) for either input or pipe close, e.g. while trying to shove the output into the side band. On msysGit, this problem was causing a hang in t5516-fetch-push. I'm not sure why (or if) this problem hasn't cropped up under Linux. The non-Windows code *does* try to check for execve() failures in the child, in addition to the fork() failures. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- run-command.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-command.c b/run-command.c index e996b21426..c13072d77c 100644 --- a/run-command.c +++ b/run-command.c @@ -385,6 +385,8 @@ fail_pipe: close(cmd->out); if (need_err) close_pair(fderr); + else if (cmd->err) + close(cmd->err); errno = failed_errno; return -1; } From 95858c276b42719b19f17f68834092e615f58e3e Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 0790/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 7ec615c5ac..643cb2473a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 78c3851c2134565bd073d6811f8bfad1c6bff3b2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0791/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 6c774de35a..2c490fa820 100644 --- a/Makefile +++ b/Makefile @@ -1856,6 +1856,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1863,6 +1864,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 7696a10bbf79aef69b94fe29582838e6dce2f02b Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0792/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 6c6cbda1db..4a08420237 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 021888175ad333dbd2b3c2867235b9413fb371fc Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0793/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 4a08420237..e0cab77412 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 848f7c3eeb72c74a6753cb1ea75db5e43414d970 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0794/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index cc639dc501..48e7b89d35 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index edc40ff574..76e0fa0525 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 51d967871b..bb700b3cb8 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f90a114b02..aeb5e8a565 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,23 +172,50 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index e0cab77412..e324e2f012 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -277,6 +274,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 9b6b1df212..67a82f055e 100644 --- a/config.c +++ b/config.c @@ -579,6 +579,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 3a43628323..801e3cfa0d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -499,4 +499,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From a3729b64d5dcd8ac7515b1587b18f11a2daa1134 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0795/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index aeb5e8a565..5a63f0feeb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 7978485a3d00a106d637d16960c1cec3bdc594ec Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0796/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 6e0ada73f68620c434ac3ff20d3b590a0ea80955 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0797/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64f05080b6..ae6bf7c219 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index f8076256b2..80f6a52ccc 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -798,6 +798,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From d8b06b7dc7c1950f5160ebd6f9ef46b25cbb86a3 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0798/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 4ca6bb2d6e9932b5d27f79b58ef151a3dbd2722a Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0799/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5a63f0feeb..25388e6fdd 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index e324e2f012..3d2f32a511 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From c34659ddff37e28a6204aaa7a2aa344b45f70523 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0800/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 25388e6fdd..a9710bc62f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1226,7 +1242,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From ef81f334674e7d3fd63a124ea84983ca8a9fefef Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0801/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From c5412ac15e3120cc040be11433aa6b3f9c5fa714 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0802/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 2f63f8a6a6a1b3bd605ddd73855011020cbf94b6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0803/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From f1a176c7c4f0da418ca35c31d6e7af12c48ef509 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0804/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From 975b3c53461e47bcea1d8f7339653aa9defa4004 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0805/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From e04acb641d84869b946a6d30008c26c32be7c62b Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0806/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 5ee2404b2ea762ba4fcb7f53072f587c79a2d4d2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0807/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 42e8a6b4e039254b68723daf5856f1596f8ff26c Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0808/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index a9710bc62f..b13f2fc22b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1283,6 +1336,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 5d5a2afa39ac414a2390c5286519ce04b4dcd45a Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0809/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index b13f2fc22b..c662964eb9 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 3d2f32a511..e30729bf84 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From cff3d87005a58038d0bd640017d2273e53ffa8fb Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0810/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 959d8d90b75ea7834fee021a971048d46f2bc78f Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 0811/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From f9c077789e824c98d138fbd3c17e17de57770fd2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 0812/3720] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..2331694bb5 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 594bac3e46b69ec668c61ffdc31affce9e633294 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 0813/3720] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2331694bb5..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9418,11 +9418,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From 3d665ed5e8aaf6a275d3707756ee73f382386f33 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 0814/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index c662964eb9..97b846535a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -343,8 +343,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -360,6 +363,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -371,12 +394,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -395,7 +418,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index e30729bf84..72a3536854 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -227,10 +227,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 2d3884a02280bf08ae6457b4a591110bf877cd17 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 0815/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 97b846535a..49e376f3db 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1568,6 +1568,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1577,9 +1578,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From bf5f38234777f35ec66f31913d8931327240ca2b Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 0816/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 675773479a..5bacf2278c 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -310,4 +310,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 80f6a52ccc..f25709854a 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -793,6 +793,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From f8f3d66cc72f8d54a2aca50ea417bd2efccd8788 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 0817/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 49e376f3db..16b32d2c16 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 0bc330ff9a1e0389a2c7c52ba5b8b8e909ddb442 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 0818/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 16b32d2c16..445b37b0d4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -373,7 +373,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From f0b93d438b4a02dd6d8554decbd4842feb60b90d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 0819/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 87ffae252b..6722386cfd 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,7 +444,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From e6324e36afc5780c385ae218dadfc935be93f836 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 0820/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -154,6 +158,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -172,6 +180,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -219,6 +231,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a9df7ff7bd..e439b0f8ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -607,6 +607,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -623,6 +627,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -649,8 +657,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -665,6 +681,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -700,6 +720,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 8192aafc1dcd6dcaa821074036e530f2c86cdbe0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 0821/3720] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index b194ea3cea..a35ef71c27 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -590,7 +590,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1012,28 +1011,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From 7723058c67380a152de54518d26bd9e00e6e0b19 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 0822/3720] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index a35ef71c27..d0af900ded 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include @@ -556,6 +557,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -781,9 +807,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -867,6 +895,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -942,6 +972,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -1010,6 +1054,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1032,6 +1099,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 99f036302a..265fa09d8d 100644 --- a/git.c +++ b/git.c @@ -329,7 +329,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 5920852953ace4ea6ac89511fb13153104c0a333 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 0823/3720] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index d0af900ded..c87db91cf4 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -807,7 +807,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -895,8 +895,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -973,16 +974,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From b63c433104e0be97119095b3ee51fae80c1f45da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 16:47:51 +0200 Subject: [PATCH 0824/3720] Replace obsolete 'diff' call with 'test_cmp' Signed-off-by: Johannes Schindelin --- t/t7002-grep.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index e249c3ed41..8a6322765c 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -60,7 +60,7 @@ do echo ${HC}file:5:foo_mmap bar mmap baz } >expected && git grep -n -w -e mmap $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (w)" ' @@ -74,7 +74,7 @@ do echo ${HC}x:1:x x xx x } >expected && git grep -n -w -e "x xx* x" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-1)" ' @@ -82,7 +82,7 @@ do echo ${HC}y:1:y yy } >expected && git grep -n -w -e "^y" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-2)" ' @@ -93,7 +93,7 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' @@ -105,14 +105,14 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' test_expect_success "grep $L (t-1)" ' echo "${HC}t/t:1:test" >expected && git grep -n -e test $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-2)" ' @@ -121,7 +121,7 @@ do cd t && git grep -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-3)" ' @@ -130,7 +130,7 @@ do cd t && git grep --full-name -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -c $L (no /dev/null)" ' From 9da886045be4c99ceb0f6e0a3b246ea82b1b1c07 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 0825/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 56 +++++++++++++++++++++++++++++++++++++++- t/t5516-fetch-push.sh | 36 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 48e7b89d35..d70eca2d7a 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1544,6 +1544,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index bb34757d27..05071c3ac1 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -18,6 +18,8 @@ enum deny_action { DENY_IGNORE, DENY_WARN, DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 02eaeec95b..3e3079ea95 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From e4d2b8a830f19800a9812820c924d699d4c39ede Mon Sep 17 00:00:00 2001 From: Ian McLean Date: Mon, 1 Mar 2010 14:58:45 -0500 Subject: [PATCH 0826/3720] Fix for issue 365: "Out of memory? mmap failed" The git_mmap implementation was broken for file sizes that wouldn't fit into a size_t (32 bits). Changed 'len' to be stored in an off_t (64 bit) variable, and moved the xsize_t cast to only occur when an attempt is made to map past the end-of-file. --- compat/win32mmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compat/win32mmap.c b/compat/win32mmap.c index 1c5a14922f..b58aa69fa0 100644 --- a/compat/win32mmap.c +++ b/compat/win32mmap.c @@ -4,19 +4,19 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of { HANDLE hmap; void *temp; - size_t len; + off_t len; struct stat st; uint64_t o = offset; uint32_t l = o & 0xFFFFFFFF; uint32_t h = (o >> 32) & 0xFFFFFFFF; if (!fstat(fd, &st)) - len = xsize_t(st.st_size); + len = st.st_size; else die("mmap: could not determine filesize"); if ((length + offset) > len) - length = len - offset; + length = xsize_t(len - offset); if (!(flags & MAP_PRIVATE)) die("Invalid usage of mmap when built with USE_WIN32_MMAP"); From 12a5a33704cd5ac56e81d87a2474589fe9509d41 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:15:40 -0400 Subject: [PATCH 0827/3720] start_command: close cmd->err descriptor when fork/spawn fails Fix the problem where the cmd->err passed into start_command wasn't being properly closed when certain types of errors occurr. (Compare the affected code with the clean shutdown code later in the function.) On Windows, this problem would be triggered if mingw_spawnvpe() failed, which would happen if the command to be executed was malformed (e.g. a text file that didn't start with a #! line). If cmd->err was a pipe, the failure to close it could result in a hang while the other side was waiting (forever) for either input or pipe close, e.g. while trying to shove the output into the side band. On msysGit, this problem was causing a hang in t5516-fetch-push. I'm not sure why (or if) this problem hasn't cropped up under Linux. The non-Windows code *does* try to check for execve() failures in the child, in addition to the fork() failures. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- run-command.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-command.c b/run-command.c index 797b4aee6a..2a1041ef65 100644 --- a/run-command.c +++ b/run-command.c @@ -383,6 +383,8 @@ fail_pipe: close(cmd->out); if (need_err) close_pair(fderr); + else if (cmd->err) + close(cmd->err); errno = failed_errno; return -1; } From c5ba0d9fa2197f8bfb6899515bae0228e8424d61 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 0828/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 445b37b0d4..8873a6c02d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 33b2e81f84875bf515b4c0de830eeddfd04227dc Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 0829/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 111c981229..8bf0071c2b 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -984,7 +984,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 401233d8bcaf944b667ecba06968cb0cd6bd9a56 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 0830/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 8bf0071c2b..ef5216fab3 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1070,7 +1070,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From f02dbc1701773693043a05c07230b3210ebc7ed0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 0831/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8873a6c02d..a77dc3a77e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 6754497c51bf48009834e274ba37d18717c22636 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 0832/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index f3d1660d02..902a9f9c21 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index a77dc3a77e..ffe20432ee 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1709,3 +1709,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index 72a3536854..bff552cb21 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -334,3 +334,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 67a82f055e..303fc48ccc 100644 --- a/config.c +++ b/config.c @@ -788,7 +788,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 801e3cfa0d..f957894b51 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -503,4 +503,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index b4c8d91722..21f20ae7f2 100644 --- a/path.c +++ b/path.c @@ -315,7 +315,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); strbuf_add(&user_path, home, strlen(home)); } else { struct passwd *pw = getpw_str(username, username_len); From eaea37334e88bb53d75c9f4d5259afed21cb5922 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:42:31 +0200 Subject: [PATCH 0833/3720] Ignore a gitweb-specific file Signed-off-by: Johannes Schindelin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 83dd1e8a45..e85d961814 100644 --- a/.gitignore +++ b/.gitignore @@ -158,6 +158,7 @@ /gitk-git/gitk-wish /gitweb/gitweb.cgi /gitweb/gitweb.min.* +/gitweb/GITWEB-BUILD-OPTIONS /test-chmtime /test-ctype /test-date From b031a931d28ac82f9650b62b8e2f36a1f3774d5b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0834/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 34b7dd5903..192c393d4b 100644 --- a/Makefile +++ b/Makefile @@ -1920,6 +1920,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1927,6 +1928,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 425d2677f21b6d8801e6960ee7903ff92df5ef35 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0835/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 3bdbd1ddf053c2ad14545d8736e0e67b2381d724 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0836/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 44edcaed283f5e75a09b829563c7b654a828cd23 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0837/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7afd0a333f..7dcc2b3278 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 5e55367bf5..f06fbdf455 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 9a8e336582..8d3f5adac8 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 9b6b1df212..67a82f055e 100644 --- a/config.c +++ b/config.c @@ -579,6 +579,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 02a73eeb66..836a8df41f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -503,4 +503,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From c605aea50201a40fd29d33b17f150d5551b9f63f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0838/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 8d3f5adac8..72f6d57465 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 64dd9e15ac59bc3e5928344c21f0dd6b1e47e72d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0839/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 7ebbde12f40dd1fe5b84864ec8f3dd8132510dfd Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0840/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64f05080b6..ae6bf7c219 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index b23a61d025..bad3e14379 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -849,6 +849,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 88b7fc288baa23a9dceea386ff5339befe865254 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0841/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 2fa4d54db88602831c38218a8a7e56f67a144d8b Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0842/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 72f6d57465..4b2f154b0f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 5642ade9326c998714370d733dc4094ae3d43cfc Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0843/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b2f154b0f..d1dc71f563 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1243,7 +1259,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 36cafb0d64648aec17a3c5968e94b6c38417b20b Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0844/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 37e82ec26478821d1407588c754f8b0d67323f7c Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0845/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 3015749583ffc750e82bdafb33f70922480b92d8 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0846/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From 9e81d04790d0778ea9fd1500031d4d475899c77a Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0847/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From 9c1c20c53c0de8edfbcdbaba35e1cf9ca61caef9 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0848/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From 7b7758ebcb7f6d6a8de90ff1cc45fe51c6713d96 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0849/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 1b541973d6a01a3a1a3056ca15c6f8b7993db603 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0850/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 1eeeb2fe255990af97f118cc987894592a2e7104 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0851/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d1dc71f563..04d6d44676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1300,6 +1353,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 7c4fed07b9fe62e253346d0b105e5df708775a92 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0852/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 04d6d44676..8839ed52d5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 04385d5866f0450b65fa9ec8540a690b6381b9aa Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0853/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From b95ac46a5beefa3b3d75e6463e213370500835f8 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 0854/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From ebbb231b9e8cb2913f52d4ece3527f298f248f0b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 0855/3720] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..2331694bb5 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 160204121d4beabeede436491c5d9ab80f5b4778 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 0856/3720] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2331694bb5..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9418,11 +9418,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From 8342c09428289e56702b04a91362132517c89224 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 0857/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8839ed52d5..38cb773315 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From bbdfb3e837ac7c67f318a568014a97204539bbee Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 0858/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 38cb773315..ee1fc7d1fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1585,6 +1585,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1594,9 +1595,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From ef7c774dde75c4b4333be7801ee5fc042996fc9d Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 0859/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7c0a698b92..56fc26e13d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -324,4 +324,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index bad3e14379..75ddb7abb5 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -844,6 +844,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 55e205d03d673762d4afd97e490f06eedbc19624 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 0860/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ee1fc7d1fa..e3a151ffd4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 6648ed6b0386380ca5d184c2e8607009e1c51649 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 0861/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e3a151ffd4..4fe094f676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 1178b3f2180d9ee06ac1ec9b28f9491a47ea9dce Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 0862/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index ef2d51a2b8..c9a78d3ed7 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From af20f56d855a079869961a9887a649a42b4c4dfd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 0863/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 9e081073fb..985dffd5ca 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 72a39dc03cc09fbcf0042f3ac6fe95cc9a4a8cc4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 0864/3720] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index d0a73da07a..4f30a9af2d 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -590,7 +590,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1016,28 +1015,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From 55c5806414572bfe9592de67ea3f9472e41bac99 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 0865/3720] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index 4f30a9af2d..b4c83a1132 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include @@ -556,6 +557,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -785,9 +811,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -871,6 +899,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -946,6 +976,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -1014,6 +1058,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1036,6 +1103,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 99f036302a..265fa09d8d 100644 --- a/git.c +++ b/git.c @@ -329,7 +329,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 6f380034d14bf9464ddaffa22926ae016d687554 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 0866/3720] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index b4c83a1132..f6657afed7 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -811,7 +811,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -899,8 +899,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -977,16 +978,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From 7c3b92c73788ca5d490189786f858ab3a846853b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 0867/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7dcc2b3278..f64aab4fb5 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1550,6 +1550,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 5a75af4155..05071c3ac1 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 62cab47a8a7059aae506c63334d195d4040c690f Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 0868/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4fe094f676..3b8107372f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 5b98a0cc3e40f18432d099c844ae8f97a95286e0 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 0869/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 111c981229..8bf0071c2b 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -984,7 +984,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 968b64b7c59aa65df7d241d53cc3ddf2e7751ff2 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 0870/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 8bf0071c2b..ef5216fab3 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1070,7 +1070,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 38ab7608d6517611eea5185741b00933f65383ec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 0871/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3b8107372f..fe13ecdfdb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From cefa4fe5e802098f2bfbc90697c7ef7bbc3bd8d3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 0872/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index f3d1660d02..902a9f9c21 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index fe13ecdfdb..4a83c617f4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1726,3 +1726,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 67a82f055e..303fc48ccc 100644 --- a/config.c +++ b/config.c @@ -788,7 +788,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 836a8df41f..1df461f256 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -507,4 +507,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index b4c8d91722..21f20ae7f2 100644 --- a/path.c +++ b/path.c @@ -315,7 +315,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); strbuf_add(&user_path, home, strlen(home)); } else { struct passwd *pw = getpw_str(username, username_len); From 04de3b041ca675fd109bafea7cce68e2ed67dafb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:42:31 +0200 Subject: [PATCH 0873/3720] Ignore a gitweb-specific file Signed-off-by: Johannes Schindelin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 14e2b6bde9..a5529c426e 100644 --- a/.gitignore +++ b/.gitignore @@ -159,6 +159,7 @@ /gitweb/GITWEB-BUILD-OPTIONS /gitweb/gitweb.cgi /gitweb/gitweb.min.* +/gitweb/GITWEB-BUILD-OPTIONS /test-chmtime /test-ctype /test-date From 734e7f52290bd00ad48eb53f78481af7e1c61daa Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Tue, 1 Jun 2010 20:41:20 +0530 Subject: [PATCH 0874/3720] Makefile: Use $(sharedir)/gitweb for target 'install-gitweb' Export gitwebdir variable so that when user types the command 'make install-gitweb', gitweb is installed in $(sharedir)/gitweb rather than /var/www/cgi-bin. Now, $(sharedir)/gitweb is default for both 'install' and 'install-gitweb' targets. Remove 'gitwebdir=$(gitwebdir_SQ)' from gitweb part of 'install' target which is unneccessary now. Signed-off-by: Pavan Kumar Sunkara Acked-by: Jakub Narebski Signed-off-by: Junio C Hamano --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cc2b3b147d..ede73cae88 100644 --- a/Makefile +++ b/Makefile @@ -286,7 +286,7 @@ lib = lib # DESTDIR= pathsep = : -export prefix bindir sharedir sysconfdir +export prefix bindir sharedir sysconfdir gitwebdir CC = gcc AR = ar @@ -1978,7 +1978,7 @@ install: all $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install ifndef NO_PERL $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install - $(MAKE) -C gitweb gitwebdir=$(gitwebdir_SQ) install + $(MAKE) -C gitweb install endif ifndef NO_PYTHON $(MAKE) -C git_remote_helpers prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install From 8b941259e6846758595818e5ca0dcb919bff28c9 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Wed, 2 Jun 2010 03:29:49 +0530 Subject: [PATCH 0875/3720] git-instaweb: Add option to reuse previous config file Add an option to git-instaweb which allows the usage of the old gitweb_config.perl situated in '.git/gitweb' dir. When the option is in use, gitweb_config.perl generated by git-instaweb won't be overwritten. Usage: git instaweb --reuse-config Example: When I use git-instaweb, it is tiring to add customised configuration (like highlight featues enabling) to the gitweb_config.perl file everytime I initiate the server. With this,it's enough to use this option. Signed-off-by: Pavan Kumar Sunkara Acked-by: Jakub Narebski Signed-off-by: Junio C Hamano --- Documentation/git-instaweb.txt | 5 ++++- git-instaweb.sh | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt index a1f17df074..7dc238f14b 100644 --- a/Documentation/git-instaweb.txt +++ b/Documentation/git-instaweb.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git instaweb' [--local] [--httpd=] [--port=] - [--browser=] + [--browser=] [--reuse-config] 'git instaweb' [--start] [--stop] [--restart] DESCRIPTION @@ -49,6 +49,9 @@ OPTIONS linkgit:git-web--browse[1] for more information about this. If the script fails, the URL will be printed to stdout. +--reuse-config:: + The previous gitweb_config.perl will not be overwritten. + --start:: Start the httpd instance and exit. This does not generate any of the configuration files for spawning a new instance. diff --git a/git-instaweb.sh b/git-instaweb.sh index 5c700b61a8..dce1e957a1 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -13,6 +13,7 @@ p,port= the port to bind to d,httpd= the command to launch b,browser= the browser to launch m,module-path= the module path (only needed for apache2) +reuse-config reuse previous gitweb_config.perl from GIT_DIR Action stop stop the web server start start the web server @@ -27,6 +28,7 @@ httpd="$(git config --get instaweb.httpd)" root="$(git config --get instaweb.gitwebdir)" port=$(git config --get instaweb.port) module_path="$(git config --get instaweb.modulepath)" +no_reuse=true conf="$GIT_DIR/gitweb/httpd.conf" @@ -151,6 +153,10 @@ do shift module_path="$1" ;; + --reuse-config) + shift + no_reuse=false + ;; --) ;; *) @@ -385,7 +391,7 @@ our \$projects_list = \$projectroot; EOF } -gitweb_conf +test "$no_reuse" = true || test ! -e "$GITWEB_CONFIG" && gitweb_conf resolve_full_httpd mkdir -p "$fqgitdir/gitweb/$httpd_only" From 33a93b326ed7e20062e896c7a82986fc9b402774 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 0876/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 75ddb7abb5..3b08a38655 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -76,6 +76,8 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export EDITOR +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 298d4c3fb2514cf152645118918e20ef79c0324a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 23:39:47 +0200 Subject: [PATCH 0877/3720] Do not use invalid reference to the heap One should never return from a function the address of data allocated on the heap in that function, because with the end of that function, the address range is freed for other purposes. Work around the thinko by making the buffer static. This is far from ideal, but a work-around. This fixes a regression introduced in 859c301(refs: split log_ref_write logic into log_ref_setup). Signed-off-by: Johannes Schindelin --- refs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/refs.c b/refs.c index 34366497b9..775f04f138 100644 --- a/refs.c +++ b/refs.c @@ -1265,7 +1265,7 @@ static int copy_msg(char *buf, const char *msg) int log_ref_setup(const char *ref_name, char **log_file) { int logfd, oflags = O_APPEND | O_WRONLY; - char logfile[PATH_MAX]; + static char logfile[PATH_MAX]; git_snpath(logfile, sizeof(logfile), "logs/%s", ref_name); *log_file = logfile; From 1086d0ff78a2875e0662a43abdfd96f221b81c13 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 0878/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From ed30c919d2238bb5f8e8710833f853006424b07f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 0879/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From 30a569d1a79a7a0e07ce3c533abc1d93f2e425e1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 12 Jun 2010 00:24:10 -0400 Subject: [PATCH 0880/3720] Revert "write-index: check and warn when worktree crosses a filesystem boundary" This reverts commit 52b98a7d2f12b5d0dd076221d40f8fa93598e11a. The goal of that commit was to warn users early when their worktree crossed filesystem boundaries. It worked by comparing the st_dev stat information in the index, and warning when we had more than one device. However, the stat information may come from multiple runs, and the st_dev field is not necessarily stable. In particular, st_dev will change on Linux across reboots. Index entries from the previous reboot will appear to come from a different device, triggering a false positive. Since this message is really only an early warning for people who will be bit by the new GIT_DISCOVERY_ACROSS_FILESYSTEM behavior, and because they will get an actual error later on (when we can't find their cross-filesystem .git directory), we can just scrap the early warning. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- read-cache.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/read-cache.c b/read-cache.c index e381ea52a3..f1f789b7b8 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1550,8 +1550,6 @@ int write_index(struct index_state *istate, int newfd) struct cache_entry **cache = istate->cache; int entries = istate->cache_nr; struct stat st; - int first_valid_ent = -1; - int more_than_one_dev; for (i = removed = extended = 0; i < entries; i++) { if (cache[i]->ce_flags & CE_REMOVE) @@ -1574,7 +1572,6 @@ int write_index(struct index_state *istate, int newfd) if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) return -1; - more_than_one_dev = 0; for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; if (ce->ce_flags & CE_REMOVE) @@ -1583,19 +1580,8 @@ int write_index(struct index_state *istate, int newfd) ce_smudge_racily_clean_entry(ce); if (ce_write_entry(&c, newfd, ce) < 0) return -1; - if (ce_uptodate(ce)) { - if (first_valid_ent < 0) - first_valid_ent = i; - else if (ce->ce_dev != cache[first_valid_ent]->ce_dev) - more_than_one_dev = 1; - } } - if (more_than_one_dev && - !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0)) - warning("working tree spans across filesystems but " - "GIT_DISCOVERY_ACROSS_FILESYSTEM is not set."); - /* Write extension data here */ if (istate->cache_tree) { struct strbuf sb = STRBUF_INIT; From c0c3928c741795b25fb305708a93ed0cb3cbd4de Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 0881/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index c9a78d3ed7..105690c7dc 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -660,7 +661,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -733,7 +735,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -757,7 +759,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From afd3af325832cf4a4396a52047fecb574ad19724 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0882/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 6ad0acacc9..71345093df 100644 --- a/Makefile +++ b/Makefile @@ -1921,6 +1921,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1928,6 +1929,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From be64d720a7d8de1909be252e1c224ab870a3d38c Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0883/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 5d1d100a4996a1462a64c777899be385292569ee Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0884/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 4fea848c1d499c3f52ec55e43accba0d4a11c40c Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0885/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7afd0a333f..7dcc2b3278 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 5e55367bf5..f06fbdf455 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 9a8e336582..8d3f5adac8 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 9b6b1df212..67a82f055e 100644 --- a/config.c +++ b/config.c @@ -579,6 +579,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 02a73eeb66..836a8df41f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -503,4 +503,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 50cb1bfbdaeb6bf7cec75ae10e0237b3269083a4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0886/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 8d3f5adac8..72f6d57465 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From e11b40abdc6265f6f606a8a518a0b5c31739c388 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0887/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 62fc6e27c917d386a58c169a04a5931f17d0303d Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0888/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64f05080b6..ae6bf7c219 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index b23a61d025..bad3e14379 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -849,6 +849,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 690cabb2b0d471dedfd208a14ca221892b8babe4 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0889/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 89983a08adbb644cd4465de54f548efce2ce8008 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0890/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 72f6d57465..4b2f154b0f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 4ba03bbfece3867cc14370f2b1908ec9a2352961 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0891/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b2f154b0f..d1dc71f563 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1243,7 +1259,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 105cb7d1f033b87b3876deef74a49c693b496e08 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0892/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From b26fe1769ee9ed7c60d6ca250514ed904445bd61 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0893/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From d2a9997bbe6c1c7cb9d470fb98d4f69076a386c4 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0894/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From 617d3353d6f448c03a517f8f5474cb922207a2df Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0895/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From 8bbb69c2f49da6ce08cecd07db034b75296a3cf0 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0896/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From 4805486feead44c2f4ec5ebf7db5ab8b4bc41778 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0897/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 7d634ec2515500d4100694c90161ae42240b54b5 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0898/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 488606f88f8bb3baa0daf6f9d7baf3543357c17a Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0899/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d1dc71f563..04d6d44676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1300,6 +1353,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From feb28d7bd6549af7e174041ca1c232a7f52a5bdf Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0900/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 04d6d44676..8839ed52d5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 494322d7762e8a68ffab7bf6180ead22aeb45698 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0901/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 2397cec9e6ac278ac2e8e30c4fa42460fdf74328 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 0902/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 2d2cd7a2f7139e3aee62044765ad33b0021760a8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 0903/3720] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..2331694bb5 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 0e2ea4305f335223caef2d88033de25f4f5ba81a Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 0904/3720] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2331694bb5..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9418,11 +9418,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From be8fa18ce394e382bb31733abd23ab222dd088d8 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 0905/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8839ed52d5..38cb773315 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 1b67fa3d98552a90eaca67897785109555c37a8a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 0906/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 38cb773315..ee1fc7d1fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1585,6 +1585,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1594,9 +1595,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From f87956d1a51ca5e99eab23804f6d76833483210e Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 0907/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7c0a698b92..56fc26e13d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -324,4 +324,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index bad3e14379..75ddb7abb5 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -844,6 +844,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 33bc9999e90ae45d325f6854e2d8adc81152ef04 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 0908/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ee1fc7d1fa..e3a151ffd4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 7b386a8a9193bce8074764edbab1bcf4f580aa55 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 0909/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e3a151ffd4..4fe094f676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 7e4a951e5609a2f26c70f2dda67861020bf5e0dc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 0910/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index ef2d51a2b8..c9a78d3ed7 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 665f9e5a2b29ba6b1fc0fd5176dd14e7e6420977 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 0911/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 9e081073fb..985dffd5ca 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From ec76125f9d761c08e28f2c55a57cf350ddae5fd9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 0912/3720] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index d0a73da07a..4f30a9af2d 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -590,7 +590,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1016,28 +1015,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From e85c0cb14f964bb2e5f1c52160a613f79a13a3d1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 0913/3720] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index 4f30a9af2d..b4c83a1132 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include @@ -556,6 +557,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -785,9 +811,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -871,6 +899,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -946,6 +976,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -1014,6 +1058,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1036,6 +1103,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 99f036302a..265fa09d8d 100644 --- a/git.c +++ b/git.c @@ -329,7 +329,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 2e07d86f48ac472b92c2cfafbe6d68528771580b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 0914/3720] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index b4c83a1132..f6657afed7 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -811,7 +811,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -899,8 +899,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -977,16 +978,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From 495281174be3612e2d8267bcc47798152ef74fdf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 0915/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7dcc2b3278..f64aab4fb5 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1550,6 +1550,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 5a75af4155..05071c3ac1 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 7f6094d149c4631123c3505b53fbb88233cc22d9 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 0916/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4fe094f676..3b8107372f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 1dfb55149af30f3c5cd57ac9d1e859e48ed6aa42 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 0917/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 111c981229..8bf0071c2b 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -984,7 +984,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 1a4b986c3273998272424d42d5996319d9069013 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 0918/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 8bf0071c2b..ef5216fab3 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1070,7 +1070,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 218abc76c9eeba72f2bd3dcd6167895ec73350df Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 0919/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3b8107372f..fe13ecdfdb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 61f99669d28105fb3eb797ebbfaac07028434cd2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 0920/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index f3d1660d02..902a9f9c21 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index fe13ecdfdb..4a83c617f4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1726,3 +1726,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 67a82f055e..303fc48ccc 100644 --- a/config.c +++ b/config.c @@ -788,7 +788,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 836a8df41f..1df461f256 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -507,4 +507,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index b4c8d91722..21f20ae7f2 100644 --- a/path.c +++ b/path.c @@ -315,7 +315,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); strbuf_add(&user_path, home, strlen(home)); } else { struct passwd *pw = getpw_str(username, username_len); From 6d48fc0ea9f7a66fd544958f52a80d3a7918a8de Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:42:31 +0200 Subject: [PATCH 0921/3720] Ignore a gitweb-specific file Signed-off-by: Johannes Schindelin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 14e2b6bde9..a5529c426e 100644 --- a/.gitignore +++ b/.gitignore @@ -159,6 +159,7 @@ /gitweb/GITWEB-BUILD-OPTIONS /gitweb/gitweb.cgi /gitweb/gitweb.min.* +/gitweb/GITWEB-BUILD-OPTIONS /test-chmtime /test-ctype /test-date From f48154a75afae32254993888462b0e294a08d200 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 0922/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 75ddb7abb5..3b08a38655 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -76,6 +76,8 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export EDITOR +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 5b82c4d7b51331ee8f4f414cd784ed848b502524 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 23:39:47 +0200 Subject: [PATCH 0923/3720] Do not use invalid reference to the heap One should never return from a function the address of data allocated on the heap in that function, because with the end of that function, the address range is freed for other purposes. Work around the thinko by making the buffer static. This is far from ideal, but a work-around. This fixes a regression introduced in 859c301(refs: split log_ref_write logic into log_ref_setup). Signed-off-by: Johannes Schindelin --- refs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/refs.c b/refs.c index 34366497b9..775f04f138 100644 --- a/refs.c +++ b/refs.c @@ -1265,7 +1265,7 @@ static int copy_msg(char *buf, const char *msg) int log_ref_setup(const char *ref_name, char **log_file) { int logfd, oflags = O_APPEND | O_WRONLY; - char logfile[PATH_MAX]; + static char logfile[PATH_MAX]; git_snpath(logfile, sizeof(logfile), "logs/%s", ref_name); *log_file = logfile; From 895184e595ddb6ab84b3001ce039ca807c6a015b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 0924/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From f25c4f92b850d4fed4b429c01c2ce8a7f51a5b1d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 0925/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From 2191a817790c970b9f5d8c9e9cc291a6aac07875 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 0926/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index c9a78d3ed7..105690c7dc 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -660,7 +661,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -733,7 +735,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -757,7 +759,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 3389c3b7975951bf4d9c63c89896467382697e74 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 17:50:57 +0200 Subject: [PATCH 0927/3720] Fix strcat() on uninitialized memory This developer wonders why we bothered with strbufs... Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 05071c3ac1..1644424585 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -569,9 +569,9 @@ static void check_aliased_update(struct command *cmd, struct string_list *list) dst_cmd->skip_update = 1; strcpy(cmd_oldh, find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV)); - strcat(cmd_newh, find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV)); + strcpy(cmd_newh, find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV)); strcpy(dst_oldh, find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV)); - strcat(dst_newh, find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV)); + strcpy(dst_newh, find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV)); rp_error("refusing inconsistent update between symref '%s' (%s..%s) and" " its target '%s' (%s..%s)", cmd->ref_name, cmd_oldh, cmd_newh, From 2fefc8d563e04f219ef4815d7530579856eaeee6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 18:05:17 +0200 Subject: [PATCH 0928/3720] Fix unchecked chdir() return value Signed-off-by: Johannes Schindelin --- builtin/grep.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index f6657afed7..a5373a473b 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -576,8 +576,9 @@ static void run_pager(struct grep_opt *opt, const char *prefix) argv[i] = path_list->items[i].string; argv[path_list->nr] = NULL; - if (prefix) - chdir(prefix); + if (prefix && chdir(prefix)) + die("Could not chdir(%s)", prefix); + execvp(argv[0], argv); error("Could not run pager %s: %s", argv[0], strerror(errno)); } From 0fe4f4467a2c2098bf03493b904a9a5e0faa010d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 0929/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 3b08a38655..3791f7ea34 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 8c8f22e9f7914be1afdc14029f5cbe2537624f59 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0930/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 9aca8a16d9..c270bbe46c 100644 --- a/Makefile +++ b/Makefile @@ -1924,6 +1924,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1931,6 +1932,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 144d4d728806efae4fcdea50d6e56d39d2ad1792 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0931/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From af63f1e48c314f88ee5e004464504e79f5720f3a Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0932/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From edd13df9fd2632171dcbcc5f96ecfa2b78755ff3 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0933/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 72949e71ac..e4caedf551 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index c9fa3df7f5..eaf6375bf5 100644 --- a/cache.h +++ b/cache.h @@ -552,6 +552,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 9a8e336582..8d3f5adac8 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index cdcf5836c6..42e94f991b 100644 --- a/config.c +++ b/config.c @@ -595,6 +595,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 83d38d3c23..ee3243c3d6 100644 --- a/environment.c +++ b/environment.c @@ -53,6 +53,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 02a73eeb66..836a8df41f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -503,4 +503,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 64b7e285ee0a4eff52184d2ca575196b24ab143f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0934/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 8d3f5adac8..72f6d57465 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 8a5fb99ce8315bb355782089d80f8b1a6a0e0d93 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0935/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 34fd2ba2caf86afaaa42b4822f5d90e7170f90a6 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0936/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64f05080b6..ae6bf7c219 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index ac496aa479..11a8aa96ca 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -885,6 +885,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From d730e59d7530df4912702a05603409ca5276f3b7 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0937/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From b79302ee2eb9ba316225408c143c24bfbb7f0e77 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0938/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 72f6d57465..4b2f154b0f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 4742aa910ec36c1963c1cdfd0e578ede97b80bf8 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0939/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b2f154b0f..d1dc71f563 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1243,7 +1259,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 082a9ce4dfc2280deab8568a0d39c90bab3c09ad Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0940/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From de84a957fd5b0aebaa8d8c05a11410155ba96f18 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0941/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 5ba1810efa9946811c13b2781c3b3f1205dc9456 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0942/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From 882c185df2bdaa1b25057d2677e0816ca3053260 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0943/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From cf2e4e7b25ee1c703082964837855a2685ac7971 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0944/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From 852746ab2b85d657912e308b5f7d4c8534542163 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0945/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 772831dab99bbc3c05c044d1fc5099ea0cc185e5 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0946/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 7467688a4bdc5ff524abe2d405270991ab204e77 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0947/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d1dc71f563..04d6d44676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1300,6 +1353,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From eacf03e96321cf88deb68eb32372b8d741be19bb Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0948/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 04d6d44676..8839ed52d5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 796f9971b250279b429bb53e0cb2c1265172f121 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0949/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 3537983d098d74ffaa1d8098c0adcd50d2ad415c Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 0950/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 7d7732903204e742310d9a7a596d4a184b393d65 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 0951/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From e88c2cacaecd5dd75dc3e53a516ae971412953f3 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 0952/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8839ed52d5..38cb773315 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 96eeac1cab42f7f0a5cebb8cab45167224e05f8a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 0953/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 38cb773315..ee1fc7d1fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1585,6 +1585,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1594,9 +1595,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From a50750568d5a18920138b42fd38c6f8d34c41b0f Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 0954/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7c0a698b92..56fc26e13d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -324,4 +324,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 11a8aa96ca..7c36654c89 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -880,6 +880,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From f083f12875cd38df84e55cf00e63a248e0f3470f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 0955/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ee1fc7d1fa..e3a151ffd4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 67c196d6e369589ad887511e89af76892374de03 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 0956/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e3a151ffd4..4fe094f676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 92186b47632dcc78009f851fc80c612aca8080d6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 0957/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..6b9f76a27d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From aa6c6d6f5edc1ef917de3c955e9af594218ae82f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 0958/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a72fe3ae64..2e210faf3c 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 720e835d34ee3cfcdfc6c686a90bf329e1f1e1fb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 0959/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index e4caedf551..72b84d0cb6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1570,6 +1570,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index d634b5a3d5..21974a0eb8 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 7c9c0b057541161d265d0963857b4b7bc3c47050 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 0960/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4fe094f676..3b8107372f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 4e07c2b14c5628bf255f1c1f19d8fd593ad98c6c Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 0961/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 6dab3bf6a7..53f89d6cd2 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1017,7 +1017,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 7c81a2897e8cf55612d6334a751b62478761929c Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 0962/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 53f89d6cd2..e157e4b469 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1103,7 +1103,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From c2b7afc7a9f10a11edc202435591692d9b499672 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 0963/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3b8107372f..fe13ecdfdb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 1258f8569e3ea1fb70adb21251dd6fb5e582e7cb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 0964/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index f3d1660d02..902a9f9c21 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index fe13ecdfdb..4a83c617f4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1726,3 +1726,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 42e94f991b..1d2410e512 100644 --- a/config.c +++ b/config.c @@ -804,7 +804,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 836a8df41f..1df461f256 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -507,4 +507,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index b4c8d91722..21f20ae7f2 100644 --- a/path.c +++ b/path.c @@ -315,7 +315,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); strbuf_add(&user_path, home, strlen(home)); } else { struct passwd *pw = getpw_str(username, username_len); From 0bb6745aafa7fb317cced06155b18087131dfe51 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:42:31 +0200 Subject: [PATCH 0965/3720] Ignore a gitweb-specific file Signed-off-by: Johannes Schindelin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 14e2b6bde9..a5529c426e 100644 --- a/.gitignore +++ b/.gitignore @@ -159,6 +159,7 @@ /gitweb/GITWEB-BUILD-OPTIONS /gitweb/gitweb.cgi /gitweb/gitweb.min.* +/gitweb/GITWEB-BUILD-OPTIONS /test-chmtime /test-ctype /test-date From f0073238db58b09e32a718f50b7f761a0ebd3cc4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 0966/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 7c36654c89..41fdba1c2d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -775,6 +775,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . ../GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 0b640087b5a61a45e96a458d8b64912d390f6ef9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 0967/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 70a6928b69d8c213ff0edb2fff8bbe82afb46bc4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 0968/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From e582acb0502d5e0d8cae6e315539ceeeba227d52 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 0969/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6b9f76a27d..ae9fc2346d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From b3dcad6c7e49521be5e68c14c32e5d4e471ead05 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 0970/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 41fdba1c2d..4c861436b7 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From fe57b3575ec0809a53a6b1392bd04288cc56a2f7 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 0971/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From a9ef3e3cfd39661119c9658ad82b127f8b155494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Sat, 10 Jul 2010 20:47:47 +0000 Subject: [PATCH 0972/3720] Add infrastructure for translating Git with gettext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All of the interface messages in Git core are currently hardcoded in English. Change that by optionally enabling translation of the core C, Shell and Perl programs via GNU or SunOS gettext. If you set the appropriate LC_* variables Git will speak your language, provided that someone has submitted a translation. If gettext isn't available, or if Git is compiled with NO_GETTEXT=YesPlease, then Git fall back on its previous behavior of only speaking English. When using ./configure the autoconf script will auto-detect if the gettext libraries are installed and act appropriately. With NO_GETTEXT=YesPlease gettext support will be #defined away for C programs. For Shell and Perl programs we rely on the git message catalog not being available. That's a reasonable assumption since then the message catalog won't be installed on the system during make install. The gettext wrappers that are provided in the patch are only the bare minimum required to begin translation work. In particular I haven't added wrappers for the gettext functions that enable plural support, or those that provide message context (msgctxt). Those can be added later. The intent is to start with a small subset and see what we need later, not to start with something that's unnecessarily large right away. Implementation and usage notes: * General: Gettext .mo files will be installed and looked for in the standard $(prefix)/share/locale path. GIT_TEXTDOMAINDIR can also be set to override that, but that's only intended to be used to test Git itself. * Perl: Perl code that wants to be localized should use the new Git::I18n module. It imports a __ function into the caller's package by default. Instead of using the high level Locale::TextDomain interface I've opted to use the low-level (equivalent to the C interface) Locale::Messages module, which Locale::TextDomain itself uses. Locale::TextDomain does a lot of redundant work we don't need, and some of it would potentially introduce bugs. It tries to set the $TEXTDOMAIN based on package of the caller, and has its own hardcoded paths where it'll search for messages. I found it easier just to completely avoid it rather than try to circumvent its behavior. In any case, this is an issue wholly internal Git::I18N. Its guts can be changed later if that's deemed necessary. See for a further elaboration on this topic. * Shell: Shell code that's to be localized should use the new git-sh-i18n library. It's just a wrapper for the system's gettext.sh. If gettext.sh isn't available we'll fall back gettext(1) if it's available. The latter is available without the former on Solaris, which has its own non-GNU gettext implementation. We also need to emulate eval_gettext() there. If neither are present we'll use a dumb printf(1) fall-through wrapper. I originally tried to detect if the system supported `echo -n' but I found this to be a waste of time. My benchmarks on Linux, Solaris and FreeBSD reveal that printf(1) is fast enough, especially since we aren't calling gettext() from within any tight loops, and unlikely to ever do so. This series has been tested by me on Ubuntu 10.04, Debian testing, FreeBSD 8.1 and SunOS 5.10, and by others on Mac OS X 10.6.3 (with Xcode 3.2.2) and openSUSE Factory (11.3, milestone 7). SunOS has its own non-GNU gettext implementation which this patch supports, although that may change in the future if it turns out that we need some GNU libintl features that SunOS doesn't provide. This patch is based on work by Jeff Epler who did the initial Makefile / C work, and a lot of comments from the Git mailing list, including Jonathan Nieder, Jakub Narebski, Johannes Sixt, Peter Krefting, Junio C Hamano, Thomas Rast and others. Signed-off-by: Ævar Arnfjörð Bjarmason Tested-By: John Wiegley Tested-by: Graham Anderson Signed-off-by: Junio C Hamano --- .gitignore | 2 + INSTALL | 12 ++++ Makefile | 69 ++++++++++++++++++++- config.mak.in | 2 + configure.ac | 12 ++++ daemon.c | 3 + fast-import.c | 3 + gettext.c | 22 +++++++ gettext.h | 18 ++++++ git-sh-i18n.sh | 71 ++++++++++++++++++++++ git.c | 3 + http-backend.c | 3 + http-fetch.c | 3 + http-push.c | 3 + imap-send.c | 3 + perl/Git/I18N.pm | 91 ++++++++++++++++++++++++++++ perl/Makefile | 3 +- perl/Makefile.PL | 14 ++++- po/.gitignore | 1 + po/is.po | 47 +++++++++++++++ shell.c | 3 + show-index.c | 3 + t/lib-gettext.sh | 42 +++++++++++++ t/t0200-gettext.sh | 113 +++++++++++++++++++++++++++++++++++ t/t0200/test.c | 13 ++++ t/t0200/test.perl | 14 +++++ t/t0200/test.sh | 14 +++++ t/t0201-gettext-fallbacks.sh | 49 +++++++++++++++ t/t0202-gettext-perl.sh | 27 +++++++++ t/t0202/test.pl | 107 +++++++++++++++++++++++++++++++++ t/test-lib.sh | 2 + upload-pack.c | 3 + 32 files changed, 771 insertions(+), 4 deletions(-) create mode 100644 gettext.c create mode 100644 gettext.h create mode 100644 git-sh-i18n.sh create mode 100644 perl/Git/I18N.pm create mode 100644 po/.gitignore create mode 100644 po/is.po create mode 100644 t/lib-gettext.sh create mode 100755 t/t0200-gettext.sh create mode 100644 t/t0200/test.c create mode 100644 t/t0200/test.perl create mode 100644 t/t0200/test.sh create mode 100755 t/t0201-gettext-fallbacks.sh create mode 100755 t/t0202-gettext-perl.sh create mode 100644 t/t0202/test.pl diff --git a/.gitignore b/.gitignore index 14e2b6bde9..6c2b1939f3 100644 --- a/.gitignore +++ b/.gitignore @@ -125,6 +125,7 @@ /git-rm /git-send-email /git-send-pack +/git-sh-i18n /git-sh-setup /git-shell /git-shortlog @@ -204,3 +205,4 @@ *.pdb /Debug/ /Release/ +/share/ diff --git a/INSTALL b/INSTALL index 61086ab120..9c9a5fa6be 100644 --- a/INSTALL +++ b/INSTALL @@ -93,6 +93,18 @@ Issues of note: history graphically, and in git-gui. If you don't want gitk or git-gui, you can use NO_TCLTK. + - A gettext library is used by default for localizing Git. The + primary target is GNU libintl, but the Solaris gettext + implementation also works. + + We need a gettext.h on the system for C code, gettext.sh (or + Solaris gettext(1)) for shell scripts, and libintl-perl for Perl + programs. + + Set NO_GETTEXT to disable localization support and make Git only + use English. Under autoconf the configure script will do this + automatically if it can't find libintl on the system. + - Some platform specific issues are dealt with Makefile rules, but depending on your specific installation, you may not have all the libraries/tools needed, or you may have diff --git a/Makefile b/Makefile index 9aca8a16d9..c97cbd8eba 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,15 @@ all:: # Define NO_EXPAT if you do not have expat installed. git-http-push is # not built, and you cannot push using http:// and https:// transports. # +# Define NO_GETTEXT if you don't want to build with Git with gettext +# support. Building it requires GNU libintl or another gettext +# implementation, and additionally libintl-perl at runtime. +# +# Define NEEDS_LIBINTL if you haven't set NO_GETTEXT and your system +# needs to be explicitly linked to -lintl. It's defined automatically +# on platforms where we don't expect glibc (Linux, Hurd, +# GNU/kFreeBSD), which includes libintl. +# # Define EXPATDIR=/foo/bar if your expat header and library files are in # /foo/bar/include and /foo/bar/lib directories. # @@ -281,6 +290,7 @@ infodir = share/info gitexecdir = libexec/git-core sharedir = $(prefix)/share gitwebdir = $(sharedir)/gitweb +localedir = $(sharedir)/locale template_dir = share/git-core/templates htmldir = share/doc/git-doc ifeq ($(prefix),/usr) @@ -294,7 +304,7 @@ lib = lib # DESTDIR= pathsep = : -export prefix bindir sharedir sysconfdir gitwebdir +export prefix bindir sharedir sysconfdir gitwebdir localedir CC = gcc AR = ar @@ -308,6 +318,8 @@ TCL_PATH = tclsh TCLTK_PATH = wish PTHREAD_LIBS = -lpthread PTHREAD_CFLAGS = +XGETTEXT = xgettext +MSGFMT = msgfmt export TCL_PATH TCLTK_PATH @@ -369,6 +381,7 @@ SCRIPT_SH += git-web--browse.sh SCRIPT_LIB += git-mergetool--lib SCRIPT_LIB += git-parse-remote SCRIPT_LIB += git-sh-setup +SCRIPT_LIB += git-sh-i18n SCRIPT_PERL += git-add--interactive.perl SCRIPT_PERL += git-difftool.perl @@ -534,6 +547,7 @@ LIB_H += userdiff.h LIB_H += utf8.h LIB_H += xdiff-interface.h LIB_H += xdiff/xdiff.h +LIB_H += gettext.h LIB_OBJS += abspath.o LIB_OBJS += advice.o @@ -575,6 +589,9 @@ LIB_OBJS += entry.o LIB_OBJS += environment.o LIB_OBJS += exec_cmd.o LIB_OBJS += fsck.o +ifndef NO_GETTEXT +LIB_OBJS += gettext.o +endif LIB_OBJS += graph.o LIB_OBJS += grep.o LIB_OBJS += hash.o @@ -747,6 +764,14 @@ EXTLIBS = # Platform specific tweaks # +# Platform specific defaults. Where we'd only like some feature on the +# minority of systems, e.g. if linking to a library isn't needed +# because its features are included in the GNU C library. +ifndef NO_GETTEXT + # Systems that use GNU gettext and glibc are the exception + NEEDS_LIBINTL = YesPlease +endif + # We choose to avoid "if .. else if .. else .. endif endif" # because maintaining the nesting to match is a pain. If # we had "elif" things would have been much nicer... @@ -762,11 +787,13 @@ ifeq ($(uname_S),Linux) NO_STRLCPY = YesPlease NO_MKSTEMPS = YesPlease HAVE_PATHS_H = YesPlease + NEEDS_LIBINTL = endif ifeq ($(uname_S),GNU/kFreeBSD) NO_STRLCPY = YesPlease NO_MKSTEMPS = YesPlease HAVE_PATHS_H = YesPlease + NEEDS_LIBINTL = endif ifeq ($(uname_S),UnixWare) CC = cc @@ -958,6 +985,7 @@ ifeq ($(uname_S),GNU) NO_STRLCPY=YesPlease NO_MKSTEMPS = YesPlease HAVE_PATHS_H = YesPlease + NEEDS_LIBINTL = endif ifeq ($(uname_S),IRIX) NO_SETENV = YesPlease @@ -1456,6 +1484,14 @@ ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT export GIT_TEST_CMP_USE_COPIED_CONTEXT endif +ifdef NO_GETTEXT + COMPAT_CFLAGS += -DNO_GETTEXT +endif + +ifdef NEEDS_LIBINTL + EXTLIBS += -lintl +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif @@ -1485,6 +1521,7 @@ ifndef V QUIET_BUILT_IN = @echo ' ' BUILTIN $@; QUIET_GEN = @echo ' ' GEN $@; QUIET_LNCP = @echo ' ' LN/CP $@; + QUIET_MSGFMT = @echo ' ' MSGFMT $@; QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ $(MAKE) $(PRINT_DIR) -C $$subdir @@ -1513,7 +1550,9 @@ template_dir_SQ = $(subst ','\'',$(template_dir)) htmldir_SQ = $(subst ','\'',$(htmldir)) prefix_SQ = $(subst ','\'',$(prefix)) gitwebdir_SQ = $(subst ','\'',$(gitwebdir)) +sharedir_SQ = $(subst ','\'',$(sharedir)) +LOCALEDIR_SQ = $(subst ','\'',$(localedir)) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH)) @@ -1563,7 +1602,7 @@ ifndef NO_TCLTK $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all endif ifndef NO_PERL - $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all + $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all endif ifndef NO_PYTHON $(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all @@ -1609,6 +1648,7 @@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ -e 's|@@DIFF@@|$(DIFF_SQ)|' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ + -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ -e $(BROKEN_PATH_FIX) \ $@.sh >$@+ @@ -1936,6 +1976,21 @@ cscope: $(RM) cscope* $(FIND) . -name '*.[hcS]' -print | xargs cscope -b +pot: + $(XGETTEXT) --add-comments --keyword=_ --keyword=N_ --output=po/git.pot --language=C $(C_OBJ:o=c) t/t0200/test.c + $(XGETTEXT) --add-comments --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH) t/t0200/test.sh + $(XGETTEXT) --add-comments --join-existing --keyword=__ --output=po/git.pot --language=Perl $(SCRIPT_PERL) t/t0200/test.perl + +POFILES := $(wildcard po/*.po) +MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES)) +MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES)) +ifndef NO_GETTEXT +all:: $(MOFILES) +endif +share/locale/%/LC_MESSAGES/git.mo: po/%.po + @mkdir -p $(dir $@) + $(QUIET_MSGFMT)$(MSGFMT) -o $@ $< + ### Detect prefix changes TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) @@ -1965,6 +2020,7 @@ endif ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@ endif + @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK @@ -2056,6 +2112,11 @@ install: all $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)' +ifndef NO_GETTEXT + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale' + (cd share && tar cf - locale) | \ + (cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -) +endif $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install ifndef NO_PERL $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install @@ -2204,6 +2265,10 @@ ifndef NO_TCLTK $(MAKE) -C git-gui clean endif $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS +ifndef NO_GETTEXT + $(RM) po/git.pot + $(RM) -r share/ +endif .PHONY: all install clean strip .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell diff --git a/config.mak.in b/config.mak.in index b4e65c32b2..011b103d1b 100644 --- a/config.mak.in +++ b/config.mak.in @@ -34,9 +34,11 @@ NO_CURL=@NO_CURL@ NO_EXPAT=@NO_EXPAT@ NO_LIBGEN_H=@NO_LIBGEN_H@ HAVE_PATHS_H=@HAVE_PATHS_H@ +NO_GETTEXT=@NO_GETTEXT@ NEEDS_LIBICONV=@NEEDS_LIBICONV@ NEEDS_SOCKET=@NEEDS_SOCKET@ NEEDS_RESOLV=@NEEDS_RESOLV@ +NEEDS_LIBINTL=@NEEDS_LIBINTL@ NEEDS_LIBGEN=@NEEDS_LIBGEN@ NO_SYS_SELECT_H=@NO_SYS_SELECT_H@ NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@ diff --git a/configure.ac b/configure.ac index 5601e8bac9..202e82084e 100644 --- a/configure.ac +++ b/configure.ac @@ -600,6 +600,12 @@ AC_CHECK_LIB([c], [basename], AC_SUBST(NEEDS_LIBGEN) test -n "$NEEDS_LIBGEN" && LIBS="$LIBS -lgen" +AC_CHECK_LIB([c], [gettext], +[NEEDS_LIBINTL=], +[NEEDS_LIBINTL=YesPlease]) +AC_SUBST(NEEDS_LIBINTL) +test -n "$NEEDS_LIBINTL" && LIBS="$LIBS -lintl" + ## Checks for header files. AC_MSG_NOTICE([CHECKS for header files]) # @@ -777,6 +783,12 @@ AC_CHECK_HEADER([paths.h], [HAVE_PATHS_H=]) AC_SUBST(HAVE_PATHS_H) # +# Define NO_GETTEXT if you don't have libintl.h +AC_CHECK_HEADER([libintl.h], +[NO_GETTEXT=], +[NO_GETTEXT=YesPlease]) +AC_SUBST(NO_GETTEXT) +# # Define NO_STRCASESTR if you don't have strcasestr. GIT_CHECK_FUNC(strcasestr, [NO_STRCASESTR=], diff --git a/daemon.c b/daemon.c index e22a2b7fa5..784f8975d4 100644 --- a/daemon.c +++ b/daemon.c @@ -3,6 +3,7 @@ #include "exec_cmd.h" #include "run-command.h" #include "strbuf.h" +#include "gettext.h" #include @@ -975,6 +976,8 @@ int main(int argc, char **argv) gid_t gid = 0; int i; + git_setup_gettext(); + git_extract_argv0_path(argv[0]); for (i = 1; i < argc; i++) { diff --git a/fast-import.c b/fast-import.c index 1e5d66ed0a..6497b0cfc0 100644 --- a/fast-import.c +++ b/fast-import.c @@ -156,6 +156,7 @@ Format of STDIN stream: #include "csum-file.h" #include "quote.h" #include "exec_cmd.h" +#include "gettext.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1< +#include +#include + +extern void git_setup_gettext(void) { + char *podir; + char *envdir = getenv("GIT_TEXTDOMAINDIR"); + + if (envdir) { + (void)bindtextdomain("git", envdir); + } else { + podir = (char *)system_path("share/locale"); + if (!podir) return; + (void)bindtextdomain("git", podir); + free(podir); + } + + (void)setlocale(LC_MESSAGES, ""); + (void)setlocale(LC_CTYPE, ""); + (void)textdomain("git"); +} diff --git a/gettext.h b/gettext.h new file mode 100644 index 0000000000..e02939ae36 --- /dev/null +++ b/gettext.h @@ -0,0 +1,18 @@ +#ifndef GETTEXT_H +#define GETTEXT_H + +#ifdef NO_GETTEXT +static inline void git_setup_gettext(void) {} +#else +extern void git_setup_gettext(void); +#endif + +#define N_(s) (s) +#ifdef NO_GETTEXT +#define _(s) (s) +#else +#include +#define _(s) gettext(s) +#endif + +#endif diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh new file mode 100644 index 0000000000..698a000fe5 --- /dev/null +++ b/git-sh-i18n.sh @@ -0,0 +1,71 @@ +#!/bin/sh +# +# Copyright (c) 2010 Ævar Arnfjörð Bjarmason +# +# This is Git's interface to gettext.sh. Use it right after +# git-sh-setup as: +# +# . git-sh-setup +# . git-sh-i18n +# +# # For constant interface messages: +# gettext "A message for the user"; echo +# +# # To interpolate variables: +# details="oh noes" +# eval_gettext "An error occured: \$details"; echo +# +# See "info '(gettext)sh'" for the full manual. + +# Export the TEXTDOMAIN* data that we need for Git +TEXTDOMAIN=git +export TEXTDOMAIN +if [ -z "$GIT_TEXTDOMAINDIR" ] +then + TEXTDOMAINDIR="@@LOCALEDIR@@" +else + TEXTDOMAINDIR="$GIT_TEXTDOMAINDIR" +fi +export TEXTDOMAINDIR + +if test -z "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" && type gettext.sh >/dev/null 2>&1 +then + # This is GNU libintl's gettext.sh, we don't need to do anything + # else than setting up the environment and loading gettext.sh + GIT_INTERNAL_GETTEXT_SH_SCHEME=gnu + export GIT_INTERNAL_GETTEXT_SH_SCHEME + + # Try to use libintl's gettext.sh, or fall back to English if we + # can't. + . gettext.sh +elif test -z "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" && test "$(gettext -h 2>&1)" = "-h" +then + # We don't have gettext.sh, but there's a gettext binary in our + # path. This is probably Solaris or something like it which has a + # gettext implementation that isn't GNU libintl. + GIT_INTERNAL_GETTEXT_SH_SCHEME=solaris + export GIT_INTERNAL_GETTEXT_SH_SCHEME + + # Solaris has a gettext(1) but no eval_gettext(1) + eval_gettext () { + gettext_out=$(gettext "$1") + gettext_eval="printf '%s' \"$gettext_out\"" + printf "%s" "`eval \"$gettext_eval\"`" + } +else + # Since gettext.sh isn't available we'll have to define our own + # dummy pass-through functions. + + # Tell our tests that we don't have the real gettext.sh + GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough + export GIT_INTERNAL_GETTEXT_SH_SCHEME + + gettext () { + printf "%s" "$1" + } + + eval_gettext () { + gettext_eval="printf '%s' \"$1\"" + printf "%s" "`eval \"$gettext_eval\"`" + } +fi diff --git a/git.c b/git.c index 265fa09d8d..95df6a6227 100644 --- a/git.c +++ b/git.c @@ -3,6 +3,7 @@ #include "cache.h" #include "quote.h" #include "run-command.h" +#include "gettext.h" const char git_usage_string[] = "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n" @@ -490,6 +491,8 @@ int main(int argc, const char **argv) if (!cmd) cmd = "git-help"; + git_setup_gettext(); + /* * "git-xxxx" is the same as "git xxxx", but we obviously: * diff --git a/http-backend.c b/http-backend.c index 14c90c2e84..502103d50d 100644 --- a/http-backend.c +++ b/http-backend.c @@ -7,6 +7,7 @@ #include "run-command.h" #include "string-list.h" #include "url.h" +#include "gettext.h" static const char content_type[] = "Content-Type"; static const char content_length[] = "Content-Length"; @@ -550,6 +551,8 @@ int main(int argc, char **argv) char *cmd_arg = NULL; int i; + git_setup_gettext(); + git_extract_argv0_path(argv[0]); set_die_routine(die_webcgi); diff --git a/http-fetch.c b/http-fetch.c index 762c750d7a..b889c36994 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -2,6 +2,7 @@ #include "exec_cmd.h" #include "http.h" #include "walker.h" +#include "gettext.h" static const char http_fetch_usage[] = "git http-fetch " "[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"; @@ -24,6 +25,8 @@ int main(int argc, const char **argv) int get_verbosely = 0; int get_recover = 0; + git_setup_gettext(); + git_extract_argv0_path(argv[0]); while (arg < argc && argv[arg][0] == '-') { diff --git a/http-push.c b/http-push.c index c9bcd11697..fc2c5f7f65 100644 --- a/http-push.c +++ b/http-push.c @@ -10,6 +10,7 @@ #include "remote.h" #include "list-objects.h" #include "sigchain.h" +#include "gettext.h" #include @@ -1791,6 +1792,8 @@ int main(int argc, char **argv) struct remote *remote; char *rewritten_url = NULL; + git_setup_gettext(); + git_extract_argv0_path(argv[0]); repo = xcalloc(sizeof(*repo), 1); diff --git a/imap-send.c b/imap-send.c index 1a577a0a09..c8fb1f9d42 100644 --- a/imap-send.c +++ b/imap-send.c @@ -25,6 +25,7 @@ #include "cache.h" #include "exec_cmd.h" #include "run-command.h" +#include "gettext.h" #ifdef NO_OPENSSL typedef void *SSL; #else @@ -1535,6 +1536,8 @@ int main(int argc, char **argv) git_extract_argv0_path(argv[0]); + git_setup_gettext(); + if (argc != 1) usage(imap_send_usage); diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm new file mode 100644 index 0000000000..5918d68847 --- /dev/null +++ b/perl/Git/I18N.pm @@ -0,0 +1,91 @@ +package Git::I18N; +use 5.006002; +use strict; +use warnings; +use Exporter; +use base 'Exporter'; + +our $VERSION = '0.01'; + +our @EXPORT = qw(__); +our @EXPORT_OK = @EXPORT; + +sub __bootstrap_locale_messages { + our $TEXTDOMAIN = 'git'; + our $TEXTDOMAINDIR = $ENV{GIT_TEXTDOMAINDIR} || '++LOCALEDIR++'; + + require POSIX; + POSIX->import(qw(setlocale)); + # Non-core prerequisite module + require Locale::Messages; + Locale::Messages->import(qw(:locale_h :libintl_h)); + + setlocale(LC_MESSAGES(), ''); + setlocale(LC_CTYPE(), ''); + textdomain($TEXTDOMAIN); + bindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR); + + return; +} + +BEGIN +{ + # Used by our test script to see if it should test fallbacks or + # not. + our $__HAS_LIBRARY = 1; + + local $@; + eval { __bootstrap_locale_messages() }; + if ($@) { + # Tell test.pl that we couldn't load the gettext library. + $Git::I18N::__HAS_LIBRARY = 0; + + # Just a fall-through no-op + *__ = sub ($) { $_[0] }; + } else { + *__ = \&Locale::Messages::gettext; + } +} + +1; + +__END__ + +=head1 NAME + +Git::I18N - Perl interface to Git's Gettext localizations + +=head1 SYNOPSIS + + use Git::I18N; + + print __("Welcome to Git!\n"); + + printf __("The following error occured: %s\n"), $error; + +=head1 DESCRIPTION + +Git's internal Perl interface to gettext via L. If +L can't be loaded (it's not a core module) we +provide stub passthrough fallbacks. + +This is a distilled interface to gettext, see C +for the full interface. This module implements only a small part of +it. + +=head1 FUNCTIONS + +=head2 __($) + +L's gettext function if all goes well, otherwise our +passthrough fallback function. + +=head1 AUTHOR + +Evar ArnfjErE Bjarmason + +=head1 COPYRIGHT + +Copyright 2010 Evar ArnfjErE Bjarmason + +=cut diff --git a/perl/Makefile b/perl/Makefile index 4ab21d61b8..4e624fff90 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -5,6 +5,7 @@ makfile:=perl.mak PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) prefix_SQ = $(subst ','\'',$(prefix)) +localedir_SQ = $(subst ','\'',$(localedir)) ifndef V QUIET = @ @@ -38,7 +39,7 @@ $(makfile): ../GIT-CFLAGS Makefile echo ' echo $(instdir_SQ)' >> $@ else $(makfile): Makefile.PL ../GIT-CFLAGS - $(PERL_PATH) $< PREFIX='$(prefix_SQ)' + $(PERL_PATH) $< PREFIX='$(prefix_SQ)' --localedir='$(localedir_SQ)' endif # this is just added comfort for calling make directly in perl dir diff --git a/perl/Makefile.PL b/perl/Makefile.PL index 0b9deca2cc..456d45bf40 100644 --- a/perl/Makefile.PL +++ b/perl/Makefile.PL @@ -1,4 +1,12 @@ +use strict; +use warnings; use ExtUtils::MakeMaker; +use Getopt::Long; + +# Sanity: die at first unknown option +Getopt::Long::Configure qw/ pass_through /; + +GetOptions("localedir=s" => \my $localedir); sub MY::postamble { return <<'MAKE_FRAG'; @@ -16,7 +24,10 @@ endif MAKE_FRAG } -my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm'); +my %pm = ( + 'Git.pm' => '$(INST_LIBDIR)/Git.pm', + 'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm', +); # We come with our own bundled Error.pm. It's not in the set of default # Perl modules so install it if it's not available on the system yet. @@ -33,6 +44,7 @@ WriteMakefile( NAME => 'Git', VERSION_FROM => 'Git.pm', PM => \%pm, + PM_FILTER => qq[\$(PERL) -pe "s<\\Q++LOCALEDIR++\\E><$localedir>"], MAKEFILE => 'perl.mak', INSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3' ); diff --git a/po/.gitignore b/po/.gitignore new file mode 100644 index 0000000000..221000e1b0 --- /dev/null +++ b/po/.gitignore @@ -0,0 +1 @@ +/*.pot diff --git a/po/is.po b/po/is.po new file mode 100644 index 0000000000..95739f1faa --- /dev/null +++ b/po/is.po @@ -0,0 +1,47 @@ +msgid "" +msgstr "" +"Project-Id-Version: Git\n" +"PO-Revision-Date: 2010-06-05 19:06 +0000\n" +"Language-Team: Git Mailing List \n" +"Report-Msgid-Bugs-To: Git Mailing List \n" +"Last-Translator: Ævar Arnfjörð Bjarmason \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: t/t0200/test.c:4 +msgid "See git help COMMAND for more information on a specific command." +msgstr "Sjá git help SKIPUN til að sjá hjálp fyrir tiltekna skipun." + +#. TRANSLATORS: This is a test. You don't need to translate it. +#: t/t0200/test.c:9 +msgid "TEST: A C test string" +msgstr "TILRAUN: C tilraunastrengur" + +#. TRANSLATORS: This is a test. You don't need to translate it. +#: t/t0200/test.c:12 +#, c-format +msgid "TEST: A C test string %s" +msgstr "TILRAUN: C tilraunastrengur %s" + +#. TRANSLATORS: This is a test. You don't need to translate it. +#: t/t0200/test.sh:8 +msgid "TEST: A Shell test string" +msgstr "TILRAUN: Skeljartilraunastrengur" + +#. TRANSLATORS: This is a test. You don't need to translate it. +#: t/t0200/test.sh:11 +#, sh-format +msgid "TEST: A Shell test $variable" +msgstr "TILRAUN: Skeljartilraunastrengur með breytunni $variable" + +#. TRANSLATORS: This is a test. You don't need to translate it. +#: t/t0200/test.perl:8 +msgid "TEST: A Perl test string" +msgstr "TILRAUN: Perl tilraunastrengur" + +#. TRANSLATORS: This is a test. You don't need to translate it. +#: t/t0200/test.perl:11 +#, perl-format +msgid "TEST: A Perl test variable %s" +msgstr "TILRAUN: Perl tilraunastrengur með breytunni %s" diff --git a/shell.c b/shell.c index e4864e04da..ba27c6be83 100644 --- a/shell.c +++ b/shell.c @@ -2,6 +2,7 @@ #include "quote.h" #include "exec_cmd.h" #include "strbuf.h" +#include "gettext.h" static int do_generic_cmd(const char *me, char *arg) { @@ -51,6 +52,8 @@ int main(int argc, char **argv) struct commands *cmd; int devnull_fd; + git_setup_gettext(); + /* * Always open file descriptors 0/1/2 to avoid clobbering files * in die(). It also avoids not messing up when the pipes are diff --git a/show-index.c b/show-index.c index 4c0ac138af..c2f5448536 100644 --- a/show-index.c +++ b/show-index.c @@ -1,5 +1,6 @@ #include "cache.h" #include "pack.h" +#include "gettext.h" static const char show_index_usage[] = "git show-index < "; @@ -11,6 +12,8 @@ int main(int argc, char **argv) unsigned int version; static unsigned int top_index[256]; + git_setup_gettext(); + if (argc != 1) usage(show_index_usage); if (fread(top_index, 2 * 4, 1, stdin) != 1) diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh new file mode 100644 index 0000000000..831ee38e83 --- /dev/null +++ b/t/lib-gettext.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# +# Copyright (c) 2010 Ævar Arnfjörð Bjarmason +# + +. ./test-lib.sh + +GIT_TEXTDOMAINDIR="$GIT_EXEC_PATH/share/locale" +GIT_PO_PATH="$GIT_EXEC_PATH/po" +export GIT_TEXTDOMAINDIR GIT_PO_PATH + +. "$GIT_EXEC_PATH"/git-sh-i18n + +if test_have_prereq GETTEXT +then + # is_IS.UTF-8 on Solaris and FreeBSD, is_IS.utf8 on Debian + is_IS_locale=$(locale -a | sed -n '/^is_IS\.[uU][tT][fF]-*8$/{ + p + q + }') + # Export it as an environmental variable so the t0202/test.pl Perl + # test can use it too + export is_IS_locale + + if test -n "$is_IS_locale" && + test $GIT_INTERNAL_GETTEXT_SH_SCHEME != "fallthrough" + then + # Some of the tests need the reference Icelandic locale + test_set_prereq GETTEXT_LOCALE + + # Exporting for t0202/test.pl + GETTEXT_LOCALE=1 + export GETTEXT_LOCALE + say "# lib-gettext: Found '$is_IS_locale' as a is_IS UTF-8 locale" + else + say "# lib-gettext: No is_IS UTF-8 locale available" + fi +else + # Only run some tests when we don't have gettext support + test_set_prereq NO_GETTEXT + say "# lib-gettext: No GETTEXT support available" +fi diff --git a/t/t0200-gettext.sh b/t/t0200-gettext.sh new file mode 100755 index 0000000000..522338d13f --- /dev/null +++ b/t/t0200-gettext.sh @@ -0,0 +1,113 @@ +#!/bin/sh +# +# Copyright (c) 2010 Ævar Arnfjörð Bjarmason +# + +test_description='Gettext support for Git' + +. ./lib-gettext.sh + +test_expect_success "sanity: \$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)" ' + test -n "$GIT_INTERNAL_GETTEXT_SH_SCHEME" +' + +test_expect_success 'sanity: $TEXTDOMAIN is git' ' + test $TEXTDOMAIN = "git" +' + +test_expect_success 'xgettext sanity: Perl _() strings are not extracted' ' + ! grep "A Perl string xgettext will not get" "$GIT_PO_PATH"/is.po +' + +test_expect_success 'xgettext sanity: Comment extraction with --add-comments' ' + grep "TRANSLATORS: This is a test" "$TEST_DIRECTORY"/t0200/* | wc -l >expect && + grep "TRANSLATORS: This is a test" "$GIT_PO_PATH"/is.po | wc -l >actual && + test_cmp expect actual +' + +test_expect_success 'xgettext sanity: Comment extraction with --add-comments stops at statements' ' + ! grep "This is a phony" "$GIT_PO_PATH"/is.po && + ! grep "the above comment" "$GIT_PO_PATH"/is.po +' + +test_expect_success GETTEXT 'sanity: $TEXTDOMAINDIR exists without NO_GETTEXT=YesPlease' ' + test -d "$TEXTDOMAINDIR" && + test "$TEXTDOMAINDIR" = "$GIT_TEXTDOMAINDIR" +' + +test_expect_success GETTEXT 'sanity: Icelandic locale was compiled' ' + test -f "$TEXTDOMAINDIR/is/LC_MESSAGES/git.mo" +' + +test_expect_success NO_GETTEXT "sanity: \$TEXTDOMAINDIR doesn't exists with NO_GETTEXT=YesPlease" ' + ! test -d "$TEXTDOMAINDIR" && + test "$TEXTDOMAINDIR" = "$GIT_TEXTDOMAINDIR" +' + +# TODO: When we have more locales, generalize this to test them +# all. Maybe we'll need a dir->locale map for that. +test_expect_success GETTEXT_LOCALE 'sanity: gettext("") metadata is OK' ' + # Return value may be non-zero + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "" >zero-expect && + grep "Project-Id-Version: Git" zero-expect && + grep "Git Mailing List " zero-expect && + grep "Content-Type: text/plain; charset=UTF-8" zero-expect && + grep "Content-Transfer-Encoding: 8bit" zero-expect +' + +test_expect_success GETTEXT_LOCALE 'sanity: gettext(unknown) is passed through' ' + printf "This is not a translation string" >expect && + gettext "This is not a translation string" >actual && + eval_gettext "This is not a translation string" >actual && + test_cmp expect actual +' + +# xgettext from C +test_expect_success GETTEXT_LOCALE 'xgettext: C extraction of _() and N_() strings' ' + printf "TILRAUN: C tilraunastrengur" >expect && + printf "\n" >>expect && + printf "Sjá git help SKIPUN til að sjá hjálp fyrir tiltekna skipun." >>expect && + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A C test string" >actual && + printf "\n" >>actual && + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "See git help COMMAND for more information on a specific command." >>actual && + test_cmp expect actual +' + +test_expect_success GETTEXT_LOCALE 'xgettext: C extraction with %s' ' + printf "TILRAUN: C tilraunastrengur %%s" >expect && + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A C test string %s" >actual && + test_cmp expect actual +' + +# xgettext from Shell +test_expect_success GETTEXT_LOCALE 'xgettext: Shell extraction' ' + printf "TILRAUN: Skeljartilraunastrengur" >expect && + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A Shell test string" >actual && + test_cmp expect actual +' + +test_expect_success GETTEXT_LOCALE 'xgettext: Shell extraction with $variable' ' + printf "TILRAUN: Skeljartilraunastrengur með breytunni a var i able" >x-expect && + LANGUAGE=is LC_ALL="$is_IS_locale" variable="a var i able" eval_gettext "TEST: A Shell test \$variable" >x-actual && + test_cmp x-expect x-actual +' + +# xgettext from Perl +test_expect_success GETTEXT_LOCALE 'xgettext: Perl extraction' ' + printf "TILRAUN: Perl tilraunastrengur" >expect && + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A Perl test string" >actual && + test_cmp expect actual +' + +test_expect_success GETTEXT_LOCALE 'xgettext: Perl extraction with %s' ' + printf "TILRAUN: Perl tilraunastrengur með breytunni %%s" >expect && + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A Perl test variable %s" >actual && + test_cmp expect actual +' + +test_expect_success GETTEXT_LOCALE 'sanity: Some gettext("") data for real locale' ' + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "" >real-locale && + test -s real-locale +' + +test_done diff --git a/t/t0200/test.c b/t/t0200/test.c new file mode 100644 index 0000000000..93373b38f7 --- /dev/null +++ b/t/t0200/test.c @@ -0,0 +1,13 @@ +/* This is a phony C program that's only here to test xgettext message extraction */ + +const char help[] = + N_("See 'git help COMMAND' for more information on a specific command."); + +int main(void) +{ + /* TRANSLATORS: This is a test. You don't need to translate it. */ + puts(_("TEST: A C test string")); + + /* TRANSLATORS: This is a test. You don't need to translate it. */ + printf(_("TEST: A C test string %s"), "variable"); +} diff --git a/t/t0200/test.perl b/t/t0200/test.perl new file mode 100644 index 0000000000..36fba341ba --- /dev/null +++ b/t/t0200/test.perl @@ -0,0 +1,14 @@ +# This is a phony Perl program that's only here to test xgettext +# message extraction + +# so the above comment won't be folded into the next one by xgettext +1; + +# TRANSLATORS: This is a test. You don't need to translate it. +print __("TEST: A Perl test string"); + +# TRANSLATORS: This is a test. You don't need to translate it. +printf __("TEST: A Perl test variable %s"), "moo"; + +# TRANSLATORS: If you see this, Git has a bug +print _"TEST: A Perl string xgettext will not get"; diff --git a/t/t0200/test.sh b/t/t0200/test.sh new file mode 100644 index 0000000000..022d607f4c --- /dev/null +++ b/t/t0200/test.sh @@ -0,0 +1,14 @@ +# This is a phony Shell program that's only here to test xgettext +# message extraction + +# so the above comment won't be folded into the next one by xgettext +echo + +# TRANSLATORS: This is a test. You don't need to translate it. +gettext "TEST: A Shell test string" + +# TRANSLATORS: This is a test. You don't need to translate it. +eval_gettext "TEST: A Shell test \$variable" + +# TRANSLATORS: If you see this, Git has a bug +_("TEST: A Shell string xgettext won't get") diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh new file mode 100755 index 0000000000..47ce4f6b6e --- /dev/null +++ b/t/t0201-gettext-fallbacks.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# +# Copyright (c) 2010 Ævar Arnfjörð Bjarmason +# + +test_description='Gettext Shell fallbacks' + +GIT_INTERNAL_GETTEXT_TEST_FALLBACKS=YesPlease +export GIT_INTERNAL_GETTEXT_TEST_FALLBACKS + +. ./lib-gettext.sh + +test_expect_success "sanity: \$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)" ' + test -n "$GIT_INTERNAL_GETTEXT_SH_SCHEME" +' + +test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_TEST_FALLBACKS is set' ' + test -n "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" +' + +test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME" is fallthrough' ' + test "$GIT_INTERNAL_GETTEXT_SH_SCHEME" = "fallthrough" +' + +test_expect_success 'gettext: our gettext() fallback has pass-through semantics' ' + printf "test" >expect && + gettext "test" >actual && + test_cmp expect actual && + printf "test more words" >expect && + gettext "test more words" >actual && + test_cmp expect actual +' + +test_expect_success 'eval_gettext: our eval_gettext() fallback has pass-through semantics' ' + printf "test" >expect && + eval_gettext "test" >actual && + test_cmp expect actual && + printf "test more words" >expect && + eval_gettext "test more words" >actual && + test_cmp expect actual +' + +test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables' ' + printf "test YesPlease" >expect && + eval_gettext "test \$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t0202-gettext-perl.sh b/t/t0202-gettext-perl.sh new file mode 100755 index 0000000000..428ebb0080 --- /dev/null +++ b/t/t0202-gettext-perl.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Copyright (c) 2010 Ævar Arnfjörð Bjarmason +# + +test_description='Perl gettext interface (Git::I18N)' + +. ./lib-gettext.sh + +if ! test_have_prereq PERL; then + skip_all='skipping perl interface tests, perl not available' + test_done +fi + +"$PERL_PATH" -MTest::More -e 0 2>/dev/null || { + skip_all="Perl Test::More unavailable, skipping test" + test_done +} + +# The external test will outputs its own plan +test_external_has_tap=1 + +test_external_without_stderr \ + 'Perl Git::I18N API' \ + "$PERL_PATH" "$TEST_DIRECTORY"/t0202/test.pl + +test_done diff --git a/t/t0202/test.pl b/t/t0202/test.pl new file mode 100644 index 0000000000..c2055fa8de --- /dev/null +++ b/t/t0202/test.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl +use 5.006002; +use lib (split(/:/, $ENV{GITPERLLIB})); +use warnings; +use strict; +use Test::More tests => 9; +use Git::I18N; +use POSIX qw(:locale_h); + +my $has_gettext_library = $Git::I18N::__HAS_LIBRARY; + +ok(1, "Testing Git::I18N version $Git::I18N::VERSION with " . + ($has_gettext_library + ? "Locale::Messages version $Locale::Messages::VERSION" + : "NO Perl gettext library")); +ok(1, "Git::I18N is located at $INC{'Git/I18N.pm'}"); + +ok($Git::I18N::VERSION, 'sanity: Git::I18N defines a $VERSION'); +{ + my $exports = @Git::I18N::EXPORT; + ok($exports, "sanity: Git::I18N has $exports export(s)"); +} +is_deeply(\@Git::I18N::EXPORT, \@Git::I18N::EXPORT_OK, "sanity: Git::I18N exports everything by default"); + +# prototypes +{ + # Add prototypes here when modifying the public interface to add + # more gettext wrapper functions. + my %prototypes = (qw( + __ $ + )); + while (my ($sub, $proto) = each %prototypes) { + is(prototype(\&{"Git::I18N::$sub"}), $proto, "sanity: $sub has a $proto prototype"); + } +} + +# Test basic passthrough in the C locale +{ + local $ENV{LANGUAGE} = 'C'; + local $ENV{LC_ALL} = 'C'; + local $ENV{LANG} = 'C'; + + my ($got, $expect) = (('TEST: A Perl test string') x 2); + + is(__($got), $expect, "Passing a string through __() in the C locale works"); +} + +# Test a basic message on different locales +SKIP: { + unless ($ENV{GETTEXT_LOCALE}) { + # Can't reliably test __() with a non-C locales because the + # required locales may not be installed on the system. + # + # We test for these anyway as part of the shell + # tests. Skipping these here will eliminate failures on odd + # platforms with incomplete locale data. + + skip "GETTEXT_LOCALE must be set by lib-gettext.sh for exhaustive Git::I18N tests", 2; + } + + # The is_IS UTF-8 locale passed from lib-gettext.sh + my $is_IS_locale = $ENV{is_IS_locale}; + + my $test = sub { + my ($got, $expect, $msg, $locale) = @_; + # Maybe this system doesn't have the locale we're trying to + # test. + my $locale_ok = setlocale(LC_ALL, $locale); + is(__($got), $expect, "$msg a gettext library + <$locale> locale <$got> turns into <$expect>"); + }; + + my $env_C = sub { + $ENV{LANGUAGE} = 'C'; + $ENV{LC_ALL} = 'C'; + }; + + my $env_is = sub { + $ENV{LANGUAGE} = 'is'; + $ENV{LC_ALL} = $is_IS_locale; + }; + + # Translation's the same as the original + my ($got, $expect) = (('TEST: A Perl test string') x 2); + + if ($has_gettext_library) { + { + local %ENV; $env_C->(); + $test->($got, $expect, "With", 'C'); + } + + { + my ($got, $expect) = ($got, 'TILRAUN: Perl tilraunastrengur'); + local %ENV; $env_is->(); + $test->($got, $expect, "With", $is_IS_locale); + } + } else { + { + local %ENV; $env_C->(); + $test->($got, $expect, "Without", 'C'); + } + + { + local %ENV; $env_is->(); + $test->($got, $expect, "Without", 'is'); + } + } +} diff --git a/t/test-lib.sh b/t/test-lib.sh index ac496aa479..4ae0de8043 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -37,6 +37,7 @@ ORIGINAL_TERM=$TERM # For repeatability, reset the environment to known value. LANG=C LC_ALL=C +LANGUAGE=C PAGER=cat TZ=UTC TERM=dumb @@ -890,6 +891,7 @@ esac test -z "$NO_PERL" && test_set_prereq PERL test -z "$NO_PYTHON" && test_set_prereq PYTHON +test -z "$NO_GETTEXT" && test_set_prereq GETTEXT # test whether the filesystem supports symbolic links ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS diff --git a/upload-pack.c b/upload-pack.c index dc464d78b3..ece9a4b4cd 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -10,6 +10,7 @@ #include "revision.h" #include "list-objects.h" #include "run-command.h" +#include "gettext.h" static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=nn] "; @@ -686,6 +687,8 @@ int main(int argc, char **argv) int i; int strict = 0; + git_setup_gettext(); + git_extract_argv0_path(argv[0]); read_replace_refs = 0; From dbaff049531c607e9bca94a43395967c6d033b5a Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 0973/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index eaf6375bf5..59886c0a8b 100644 --- a/cache.h +++ b/cache.h @@ -718,7 +718,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index 4a83c617f4..861d3dad35 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1744,3 +1744,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 1df461f256..8239679b32 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -179,6 +179,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 21f20ae7f2..a121fbd204 100644 --- a/path.c +++ b/path.c @@ -728,10 +728,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 714ccc6361d72e6ee28acbc969cfe3a6a5337dfb Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 0974/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 902a9f9c21..8b5069f712 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 185df65ac72376d323257ca4e6f4441fc9fece34 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 0975/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 861d3dad35..81c8b2e172 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1747,23 +1747,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 02f9c7c96ef2aeb6476d8972e42d7ece15107c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Mon, 19 Jul 2010 20:28:11 +0000 Subject: [PATCH 0976/3720] tests: rename test to work around GNU gettext bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename t0200-gettext.sh to t0200-gettext-basic.sh. Versions of GNU gettext before v0.15 (released in 2006) fail to run the test because of an old bug in gettext.sh. To conform with the FHS gettext.sh prints a help message when it's invoked directly. To do this it checks if $0 is "gettext.sh". This check was broken before v0.15, it was checking for *\gettext.sh (to support Windows), but now correctly checks for *\\gettext.sh. t0200-gettext.sh matched the former broken check, so on systems with an old GNU gettext (like RHEL 5.4) the test simply printed: ./t0200-gettext.sh GNU gettext shell script function library version 0.14.6 Usage: . gettext.sh FATAL: Unexpected exit with code 1 Which is just the gettext.sh help output: $ gettext.sh GNU gettext shell script function library version 0.17 Usage: . gettext.sh Change the test name to t0200-gettext-basic.sh to work around that. Reported-by: Thomas Rast Signed-off-by: Ævar Arnfjörð Bjarmason Tested-by: Thomas Rast Signed-off-by: Junio C Hamano --- t/{t0200-gettext.sh => t0200-gettext-basic.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename t/{t0200-gettext.sh => t0200-gettext-basic.sh} (100%) diff --git a/t/t0200-gettext.sh b/t/t0200-gettext-basic.sh similarity index 100% rename from t/t0200-gettext.sh rename to t/t0200-gettext-basic.sh From ecdbd4a9c53014c4995baa9e3eeb9324ad560e23 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 17:40:44 +0200 Subject: [PATCH 0977/3720] Make sure that git_getpass() never returns NULL The result of git_getpass() is used without checking for NULL, so let's just die() instead of returning NULL. Signed-off-by: Johannes Schindelin --- connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 02e738a014..d3e967fcd9 100644 --- a/connect.c +++ b/connect.c @@ -628,8 +628,12 @@ char *git_getpass(const char *prompt) askpass = getenv("GIT_ASKPASS"); - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; From 1644f8ea01598a2830b6413d3d5d6fb106ade337 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 0978/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 395cb2e35f..32c1c15d51 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 65a77451ccb73f978dd78fd021274828a056a809 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 0979/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 5074715deb89bbe33c058a3b8b592f8f27ef107b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 0980/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index f33648da01..7c0ff3187c 100644 --- a/Makefile +++ b/Makefile @@ -1924,6 +1924,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1931,6 +1932,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From cb8ba3ddfa728a192385719ef6a1cf3c1854ee44 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 0981/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 0547dc22449e31d236d5674588a34d6e25c4cf9e Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 0982/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 29a41a89ffaac75356aee852a2b14e77e5ab234d Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 0983/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f81fb918da..c3b78d6d4d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index c9fa3df7f5..eaf6375bf5 100644 --- a/cache.h +++ b/cache.h @@ -552,6 +552,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 9a8e336582..8d3f5adac8 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index cdcf5836c6..42e94f991b 100644 --- a/config.c +++ b/config.c @@ -595,6 +595,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 83d38d3c23..ee3243c3d6 100644 --- a/environment.c +++ b/environment.c @@ -53,6 +53,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 02a73eeb66..836a8df41f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -503,4 +503,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 6733fc89f7af7de6aafb28261e46ba9fa144b83e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 0984/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 8d3f5adac8..72f6d57465 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From f2c6cc71e5ea19fbb357513d20f24024df647392 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 0985/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 0d6ad115099165884030d975daa70f4b72960ba8 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 0986/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..1eaa83f686 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NONMINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NONMINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/test-lib.sh b/t/test-lib.sh index e5523dd690..eeb66d9082 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -878,6 +878,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From d523415253652ea1ad3a3a2d74916b9a6d23a563 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 0987/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 5c66a7bcd64d877a30d086da942ba9471c6c9d5e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 0988/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 72f6d57465..4b2f154b0f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From c70f14f4d0b221d94b487d0cf8d7cba831603bed Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 0989/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b2f154b0f..d1dc71f563 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1243,7 +1259,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 4784ecfb32e19af5541f7466ba63d7adc6a5e097 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 0990/3720] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 49321ed05623dc597b5d54c7dc6b74c9467ac9af Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 0991/3720] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From b351b0f84503be7f940fea7e59dd03b4763f535c Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 0992/3720] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From 477b4eff3dd502fb083efdcefbd9ccb60d771f37 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 0993/3720] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From a3fccf887764291d16104a033ea4cf585608c6fa Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 0994/3720] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From 3ad40252882922d4e6721e4dff4f0ab16dddfab4 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 0995/3720] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From bf23433a2e056ca0f6e27239499445b62cdfe3a6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 0996/3720] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From aaadb88d8acc32dc37a39017c336e64883171f27 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 0997/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d1dc71f563..04d6d44676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1300,6 +1353,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 5883b116fc14ebd43642b55ae0093ced37aa12f5 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 0998/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 04d6d44676..8839ed52d5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 3c6aa0ddfc214499eb9c7b7e40f2b0c76057436a Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 0999/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From a4c7c0529e2427fed03059f40c55749238dc8d8f Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 1000/3720] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From d78be192c790d400170ae76582bd066b88f877a0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1001/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 91c04d17e389544389e66dafda3638f24137f817 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1002/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8839ed52d5..38cb773315 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From d04edec8aa92288b3f4f6f21bf64ecca3500f402 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1003/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 38cb773315..ee1fc7d1fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1585,6 +1585,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1594,9 +1595,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 1f086d444f3cc78700c11f15f9fba9741799147a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1004/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7c0a698b92..56fc26e13d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -324,4 +324,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index eeb66d9082..fc21750820 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -873,6 +873,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 3a836536f8fee257a41c39f68a47569c50fb606e Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1005/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ee1fc7d1fa..e3a151ffd4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 1e750881183117cc9bcc91c387dbfdab53dfbfab Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 1006/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e3a151ffd4..4fe094f676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 9d210efdfa4e182b0d7e13d666e742dd22e5b0ad Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 1007/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..6b9f76a27d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 65587c4ca48b970c550c52e1f42ef71eb79a4dac Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1008/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a72fe3ae64..2e210faf3c 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 6f2e26e6b6841e62da7cb706db2f317eab5c0ff4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1009/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c3b78d6d4d..29a3c7f008 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1576,6 +1576,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index d634b5a3d5..21974a0eb8 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 92283f7e8e2525540bfff78cdb595e2fe123b408 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1010/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4fe094f676..3b8107372f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 898a0d8c1ecd973c85eea5d18f741bb392e03a2f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1011/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 6dab3bf6a7..53f89d6cd2 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1017,7 +1017,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 68bc3d900fe8e838a6389598d819aac97ef2018c Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1012/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 53f89d6cd2..e157e4b469 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1103,7 +1103,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From d10116a95634ef4eabe9b7802ef240bf86347abb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1013/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3b8107372f..fe13ecdfdb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From c0121bd808ed017f60812f3ec4eb7fefb6876664 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1014/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index f3d1660d02..902a9f9c21 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index fe13ecdfdb..4a83c617f4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1726,3 +1726,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 42e94f991b..1d2410e512 100644 --- a/config.c +++ b/config.c @@ -804,7 +804,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 836a8df41f..1df461f256 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -507,4 +507,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 6b23023095..6345b23876 100644 --- a/path.c +++ b/path.c @@ -315,7 +315,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From d9a9614aa94750b49a59c911ee0e3c7379070029 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:42:31 +0200 Subject: [PATCH 1015/3720] Ignore a gitweb-specific file Signed-off-by: Johannes Schindelin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 14e2b6bde9..a5529c426e 100644 --- a/.gitignore +++ b/.gitignore @@ -159,6 +159,7 @@ /gitweb/GITWEB-BUILD-OPTIONS /gitweb/gitweb.cgi /gitweb/gitweb.min.* +/gitweb/GITWEB-BUILD-OPTIONS /test-chmtime /test-ctype /test-date From e357fcd50be7f421a2012aaf974b630ce6593528 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1016/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index fc21750820..a3e1867dee 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -776,6 +776,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . ../GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 2f5b603227070fccd40a1687c9496fe5d7afe3b2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1017/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 10398d40f3929773f56846938f2db1ccde8e0549 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1018/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From d8041b2dead7f367a48eb568e5e4ac7f759484de Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1019/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6b9f76a27d..ae9fc2346d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From f14a8fd1f7461082f98e3e58857ce5b37555059c Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1020/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index a3e1867dee..4566f52a5d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 5a43b047495a11349d42842e6f5af3540d80d782 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1021/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From 8731347ee8432bf9c17a42626b362670f4fc09a8 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1022/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index eaf6375bf5..59886c0a8b 100644 --- a/cache.h +++ b/cache.h @@ -718,7 +718,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index 4a83c617f4..861d3dad35 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1744,3 +1744,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 1df461f256..8239679b32 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -179,6 +179,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 6345b23876..3870b2411a 100644 --- a/path.c +++ b/path.c @@ -730,10 +730,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From f208f12d5baf50f8e04329b2cf82e2e4de9f5791 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1023/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 902a9f9c21..8b5069f712 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 388423d1bd18e0ba6f14253dd5c656651d404512 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1024/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 861d3dad35..81c8b2e172 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1747,23 +1747,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From e3b6034066441b9f79e764d01fa40cfa958badb4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 17:40:44 +0200 Subject: [PATCH 1025/3720] Make sure that git_getpass() never returns NULL The result of git_getpass() is used without checking for NULL, so let's just die() instead of returning NULL. Signed-off-by: Johannes Schindelin --- connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 02e738a014..d3e967fcd9 100644 --- a/connect.c +++ b/connect.c @@ -628,8 +628,12 @@ char *git_getpass(const char *prompt) askpass = getenv("GIT_ASKPASS"); - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; From 4ed8d6607e9d6f4752ac39d5dccc52b70426a528 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1026/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 395cb2e35f..32c1c15d51 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 8ab2896cda5a9d2461e24bdacde8311deed88483 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1027/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 6ce977caf5c530ea09c2beafdc995a82d29d4d4d Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Mon, 26 Jul 2010 20:27:50 +0200 Subject: [PATCH 1028/3720] Submodules: Add the new "ignore" config option for diff and status The new "ignore" config option controls the default behavior for "git status" and the diff family. It specifies under what circumstances they consider submodules as modified and can be set separately for each submodule. The command line option "--ignore-submodules=" has been extended to accept the new parameter "none" for both status and diff. Users that chose submodules to get rid of long work tree scanning times might want to set the "dirty" option for those submodules. This brings back the pre 1.7.0 behavior, where submodule work trees were never scanned for modifications. By using "--ignore-submodules=none" on the command line the status and diff commands can be told to do a full scan. This option can be set to the following values (which have the same name and meaning as for the "--ignore-submodules" option of status and diff): "all": All changes to the submodule will be ignored. "dirty": Only differences of the commit recorded in the superproject and the submodules HEAD will be considered modifications, all changes to the work tree of the submodule will be ignored. When using this value, the submodule will not be scanned for work tree changes at all, leading to a performance benefit on large submodules. "untracked": Only untracked files in the submodules work tree are ignored, a changed HEAD and/or modified files in the submodule will mark it as modified. "none" (which is the default): Either untracked or modified files in a submodules work tree or a difference between the subdmodules HEAD and the commit recorded in the superproject will make it show up as changed. This value is added as a new parameter for the "--ignore-submodules" option of the diff family and "git status" so the user can override the settings in the configuration. Signed-off-by: Jens Lehmann Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 10 ++++ Documentation/diff-options.txt | 6 ++- Documentation/git-status.txt | 6 ++- diff-lib.c | 15 ++++-- diff.c | 35 ++++++++++--- diff.h | 1 + submodule.c | 51 ++++++++++++++++++- submodule.h | 3 ++ t/t4027-diff-submodule.sh | 73 ++++++++++++++++++++++++++ t/t7508-status.sh | 93 ++++++++++++++++++++++++++++++++-- wt-status.c | 8 ++- 11 files changed, 281 insertions(+), 20 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 29a3c7f008..b03ee4b087 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1758,6 +1758,16 @@ submodule..update:: URL and other values found in the `.gitmodules` file. See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. +submodule..ignore:: + Defines under what circumstances "git status" and the diff family show + a submodule as modified. When set to "all", it will never be considered + modified, "dirty" will ignore all changes to the submodules work tree and + takes only differences between the HEAD of the submodule and the commit + recorded in the superproject into account. "untracked" will additionally + let submodules with modified tracked files in their work tree show up. + Using "none" (the default when this option is not set) also shows + submodules that have untracked files in their work tree as changed. + tar.umask:: This variable can be used to restrict the permission bits of tar archive entries. The default is 0002, which turns off the diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 2371262b10..9cf7506626 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -330,7 +330,11 @@ endif::git-format-patch[] --ignore-submodules[=]:: Ignore changes to submodules in the diff generation. can be - either "untracked", "dirty" or "all", which is the default. When + either "none", "untracked", "dirty" or "all", which is the default + Using "none" will consider the submodule modified when it either contains + untracked or modified files or its HEAD differs from the commit recorded + in the superproject and can be used to override any settings of the + 'ignore' option in linkgit:git-config[1]. When "untracked" is used submodules are not considered dirty when they only contain untracked content (but they are still scanned for modified content). Using "dirty" ignores all changes to the work tree of submodules, diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index 2fd054c104..a7a5d79416 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -55,7 +55,11 @@ specified. --ignore-submodules[=]:: Ignore changes to submodules when looking for changes. can be - either "untracked", "dirty" or "all", which is the default. When + either "none", "untracked", "dirty" or "all", which is the default. + Using "none" will consider the submodule modified when it either contains + untracked or modified files or its HEAD differs from the commit recorded + in the superproject and can be used to override any settings of the + 'ignore' option in linkgit:git-config[1]. When "untracked" is used submodules are not considered dirty when they only contain untracked content (but they are still scanned for modified content). Using "dirty" ignores all changes to the work tree of submodules, diff --git a/diff-lib.c b/diff-lib.c index 8b8978ae6d..392ce2bef0 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -68,11 +68,16 @@ static int match_stat_with_submodule(struct diff_options *diffopt, unsigned ce_option, unsigned *dirty_submodule) { int changed = ce_match_stat(ce, st, ce_option); - if (S_ISGITLINK(ce->ce_mode) - && !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES) - && !DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES) - && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES))) { - *dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES)); + if (S_ISGITLINK(ce->ce_mode)) { + unsigned orig_flags = diffopt->flags; + if (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG)) + set_diffopt_flags_from_submodule_config(diffopt, ce->name); + if (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)) + changed = 0; + else if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES) + && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES))) + *dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES)); + diffopt->flags = orig_flags; } return changed; } diff --git a/diff.c b/diff.c index 17873f3d9e..8206047314 100644 --- a/diff.c +++ b/diff.c @@ -141,6 +141,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } + if (!prefixcmp(var, "submodule.")) + return parse_submodule_config_option(var, value); + return git_color_default_config(var, value, cb); } @@ -3166,11 +3169,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_SET(options, ALLOW_TEXTCONV); else if (!strcmp(arg, "--no-textconv")) DIFF_OPT_CLR(options, ALLOW_TEXTCONV); - else if (!strcmp(arg, "--ignore-submodules")) + else if (!strcmp(arg, "--ignore-submodules")) { + DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(options, "all"); - else if (!prefixcmp(arg, "--ignore-submodules=")) + } else if (!prefixcmp(arg, "--ignore-submodules=")) { + DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(options, arg + 20); - else if (!strcmp(arg, "--submodule")) + } else if (!strcmp(arg, "--submodule")) DIFF_OPT_SET(options, SUBMODULE_LOG); else if (!prefixcmp(arg, "--submodule=")) { if (!strcmp(arg + 12, "log")) @@ -4103,6 +4108,24 @@ int diff_result_code(struct diff_options *opt, int status) return result; } +/* + * Shall changes to this submodule be ignored? + * + * Submodule changes can be configured to be ignored separately for each path, + * but that configuration can be overridden from the command line. + */ +static int is_submodule_ignored(const char *path, struct diff_options *options) +{ + int ignored = 0; + unsigned orig_flags = options->flags; + if (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG)) + set_diffopt_flags_from_submodule_config(options, path); + if (DIFF_OPT_TST(options, IGNORE_SUBMODULES)) + ignored = 1; + options->flags = orig_flags; + return ignored; +} + void diff_addremove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, @@ -4110,7 +4133,7 @@ void diff_addremove(struct diff_options *options, { struct diff_filespec *one, *two; - if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(mode)) + if (S_ISGITLINK(mode) && is_submodule_ignored(concatpath, options)) return; /* This may look odd, but it is a preparation for @@ -4157,8 +4180,8 @@ void diff_change(struct diff_options *options, { struct diff_filespec *one, *two; - if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(old_mode) - && S_ISGITLINK(new_mode)) + if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) && + is_submodule_ignored(concatpath, options)) return; if (DIFF_OPT_TST(options, REVERSE_DIFF)) { diff --git a/diff.h b/diff.h index 063d10ac22..53ad345469 100644 --- a/diff.h +++ b/diff.h @@ -77,6 +77,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data) #define DIFF_OPT_DIRTY_SUBMODULES (1 << 24) #define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25) #define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26) +#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) diff --git a/submodule.c b/submodule.c index 61cb6e21dd..d35a14dc06 100644 --- a/submodule.c +++ b/submodule.c @@ -6,6 +6,9 @@ #include "revision.h" #include "run-command.h" #include "diffcore.h" +#include "string-list.h" + +struct string_list config_ignore; static int add_submodule_odb(const char *path) { @@ -46,6 +49,52 @@ done: return ret; } +void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, + const char *path) +{ + struct string_list_item *ignore_option; + ignore_option = unsorted_string_list_lookup(&config_ignore, path); + if (ignore_option) + handle_ignore_submodules_arg(diffopt, ignore_option->util); +} + +static int submodule_config(const char *var, const char *value, void *cb) +{ + if (!prefixcmp(var, "submodule.")) + return parse_submodule_config_option(var, value); + return 0; +} + +int parse_submodule_config_option(const char *var, const char *value) +{ + int len; + struct string_list_item *ignore_option; + struct strbuf path = STRBUF_INIT; + + var += 10; /* Skip "submodule." */ + + len = strlen(var); + if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { + if (strcmp(value, "untracked") && strcmp(value, "dirty") && + strcmp(value, "all") && strcmp(value, "none")) { + warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var); + return 0; + } + + strbuf_add(&path, var, len - 7); + ignore_option = unsorted_string_list_lookup(&config_ignore, path.buf); + if (ignore_option) + free(ignore_option->util); + else + ignore_option = string_list_append(&config_ignore, + strbuf_detach(&path, NULL)); + strbuf_release(&path); + ignore_option->util = xstrdup(value); + return 0; + } + return 0; +} + void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *arg) { @@ -55,7 +104,7 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt, DIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES); else if (!strcmp(arg, "dirty")) DIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES); - else + else if (strcmp(arg, "none")) die("bad --ignore-submodules argument: %s", arg); } diff --git a/submodule.h b/submodule.h index 6fd3bb4070..185a5ce6c6 100644 --- a/submodule.h +++ b/submodule.h @@ -3,6 +3,9 @@ struct diff_options; +void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, + const char *path); +int parse_submodule_config_option(const char *var, const char *value); void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *); void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index 1bd8e5ee3a..5022fa0b20 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -114,6 +114,30 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)' ! test -s actual4 ' +test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.git/config]' ' + git config submodule.sub.ignore none && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config submodule.sub.ignore all && + git diff HEAD >actual2 && + ! test -s actual2 && + git config submodule.sub.ignore untracked && + git diff HEAD >actual3 && + sed -e "1,/^@@/d" actual3 >actual3.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual3.body && + git config submodule.sub.ignore dirty && + git diff HEAD >actual4 && + ! test -s actual4 && + git diff HEAD --ignore-submodules=none >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config --remove-section submodule.sub +' + test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' ' ( cd sub && @@ -146,6 +170,55 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)' ! test -s actual4 ' +test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.git/config]' ' + git config submodule.sub.ignore all && + git diff HEAD >actual2 && + ! test -s actual2 && + git config submodule.sub.ignore untracked && + git diff HEAD >actual3 && + ! test -s actual3 && + git config submodule.sub.ignore dirty && + git diff HEAD >actual4 && + ! test -s actual4 && + git diff --ignore-submodules=none HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config --remove-section submodule.sub +' + +test_expect_success 'git diff between submodule commits' ' + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git diff --ignore-submodules=dirty HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git diff --ignore-submodules HEAD^..HEAD >actual && + ! test -s actual +' + +test_expect_success 'git diff between submodule commits [.git/config]' ' + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git config submodule.sub.ignore dirty && + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git config submodule.sub.ignore all && + git diff HEAD^..HEAD >actual && + ! test -s actual && + git diff --ignore-submodules=dirty HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + git config --remove-section submodule.sub +' + test_expect_success 'git diff (empty submodule dir)' ' : >empty && rm -rf sub/* sub/.git && diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 2e210faf3c..e01b2a38cd 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -832,24 +832,38 @@ test_expect_success POSIXPERM 'status succeeds in a read-only repository' ' (exit $status) ' +(cd sm && echo > bar && git add bar && git commit -q -m 'Add bar' && cd .. && git add sm) +new_head=$(cd sm && git rev-parse --short=7 --verify HEAD) +touch .gitmodules + cat > expect << EOF # On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# modified: sm +# # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # modified: dir1/modified # +# Submodule changes to be committed: +# +# * sm $head...$new_head (1): +# > Add bar +# # Untracked files: # (use "git add ..." to include in what will be committed) # +# .gitmodules # dir1/untracked # dir2/modified # dir2/untracked # expect # output # untracked -no changes added to commit (use "git add" and/or "git commit -a") EOF test_expect_success '--ignore-submodules=untracked suppresses submodules with untracked content' ' @@ -858,19 +872,45 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un test_cmp expect output ' +test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' ' + git config --add submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' ' git status --ignore-submodules=dirty > output && test_cmp expect output ' +test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' ' + git config --add submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' ' echo modified > sm/foo && git status --ignore-submodules=dirty > output && test_cmp expect output ' +test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' ' + git config --add submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + cat > expect << EOF # On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# modified: sm +# # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) @@ -879,16 +919,21 @@ cat > expect << EOF # modified: dir1/modified # modified: sm (modified content) # +# Submodule changes to be committed: +# +# * sm $head...$new_head (1): +# > Add bar +# # Untracked files: # (use "git add ..." to include in what will be committed) # +# .gitmodules # dir1/untracked # dir2/modified # dir2/untracked # expect # output # untracked -no changes added to commit (use "git add" and/or "git commit -a") EOF test_expect_success "--ignore-submodules=untracked doesn't suppress submodules with modified content" ' @@ -896,10 +941,22 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodules w test_cmp expect output ' +test_expect_success ".git/config ignore=untracked doesn't suppress submodules with modified content" ' + git config --add submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + head2=$(cd sm && git commit -q -m "2nd commit" foo && git rev-parse --short=7 --verify HEAD) cat > expect << EOF # On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# modified: sm +# # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) @@ -907,21 +964,26 @@ cat > expect << EOF # modified: dir1/modified # modified: sm (new commits) # +# Submodule changes to be committed: +# +# * sm $head...$new_head (1): +# > Add bar +# # Submodules changed but not updated: # -# * sm $head...$head2 (1): +# * sm $new_head...$head2 (1): # > 2nd commit # # Untracked files: # (use "git add ..." to include in what will be committed) # +# .gitmodules # dir1/untracked # dir2/modified # dir2/untracked # expect # output # untracked -no changes added to commit (use "git add" and/or "git commit -a") EOF test_expect_success "--ignore-submodules=untracked doesn't suppress submodule summary" ' @@ -929,11 +991,26 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodule su test_cmp expect output ' +test_expect_success ".git/config ignore=untracked doesn't suppress submodule summary" ' + git config --add submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summary" ' git status --ignore-submodules=dirty > output && test_cmp expect output ' +test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary" ' + git config --add submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + + cat > expect << EOF # On branch master # Changed but not updated: @@ -945,6 +1022,7 @@ cat > expect << EOF # Untracked files: # (use "git add ..." to include in what will be committed) # +# .gitmodules # dir1/untracked # dir2/modified # dir2/untracked @@ -959,4 +1037,11 @@ test_expect_success "--ignore-submodules=all suppresses submodule summary" ' test_cmp expect output ' +test_expect_failure '.git/config ignore=all suppresses submodule summary' ' + git config --add submodule.sm.ignore all && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + test_done diff --git a/wt-status.c b/wt-status.c index 2f9e33c8fa..54b6b03b9c 100644 --- a/wt-status.c +++ b/wt-status.c @@ -313,8 +313,10 @@ static void wt_status_collect_changes_worktree(struct wt_status *s) DIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES); if (!s->show_untracked_files) DIFF_OPT_SET(&rev.diffopt, IGNORE_UNTRACKED_IN_SUBMODULES); - if (s->ignore_submodule_arg) + if (s->ignore_submodule_arg) { + DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg); + } rev.diffopt.format_callback = wt_status_collect_changed_cb; rev.diffopt.format_callback_data = s; rev.prune_data = s->pathspec; @@ -331,8 +333,10 @@ static void wt_status_collect_changes_index(struct wt_status *s) opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference; setup_revisions(0, NULL, &rev, &opt); - if (s->ignore_submodule_arg) + if (s->ignore_submodule_arg) { + DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg); + } rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = wt_status_collect_updated_cb; From 4c8389b25763d70b6d6defa39dd0e6aa760c6029 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Mon, 26 Jul 2010 20:28:31 +0200 Subject: [PATCH 1029/3720] Submodules: Use "ignore" settings from .gitmodules too for diff and status The .gitmodules file is parsed for "submodule..ignore" entries before looking for them in .git/config. Thus settings found in .git/config will override those from .gitmodules, thereby allowing the local developer to ignore settings given by the remote side while also letting upstream set defaults for those users who don't have special needs. Signed-off-by: Jens Lehmann Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 3 ++ Documentation/diff-options.txt | 2 +- Documentation/git-status.txt | 2 +- Documentation/gitmodules.txt | 15 ++++++++ builtin/commit.c | 2 ++ builtin/diff-files.c | 2 ++ builtin/diff-index.c | 2 ++ builtin/diff-tree.c | 2 ++ builtin/diff.c | 2 ++ submodule.c | 12 +++++++ submodule.h | 1 + t/t4027-diff-submodule.sh | 66 ++++++++++++++++++++++++++++++++++ t/t7508-status.sh | 63 +++++++++++++++++++++++++++++++- 13 files changed, 171 insertions(+), 3 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index b03ee4b087..5594ce04ff 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1767,6 +1767,9 @@ submodule..ignore:: let submodules with modified tracked files in their work tree show up. Using "none" (the default when this option is not set) also shows submodules that have untracked files in their work tree as changed. + This setting overrides any setting made in .gitmodules for this submodule, + both settings can be overriden on the command line by using the + "--ignore-submodule" option. tar.umask:: This variable can be used to restrict the permission bits of diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 9cf7506626..faa467b032 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -334,7 +334,7 @@ endif::git-format-patch[] Using "none" will consider the submodule modified when it either contains untracked or modified files or its HEAD differs from the commit recorded in the superproject and can be used to override any settings of the - 'ignore' option in linkgit:git-config[1]. When + 'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When "untracked" is used submodules are not considered dirty when they only contain untracked content (but they are still scanned for modified content). Using "dirty" ignores all changes to the work tree of submodules, diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index a7a5d79416..dae190a5f2 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -59,7 +59,7 @@ specified. Using "none" will consider the submodule modified when it either contains untracked or modified files or its HEAD differs from the commit recorded in the superproject and can be used to override any settings of the - 'ignore' option in linkgit:git-config[1]. When + 'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When "untracked" is used submodules are not considered dirty when they only contain untracked content (but they are still scanned for modified content). Using "dirty" ignores all changes to the work tree of submodules, diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index 72a13d18e0..8ae107da25 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -44,6 +44,21 @@ submodule..update:: This config option is overridden if 'git submodule update' is given the '--merge' or '--rebase' options. +submodule..ignore:: + Defines under what circumstances "git status" and the diff family show + a submodule as modified. When set to "all", it will never be considered + modified, "dirty" will ignore all changes to the submodules work tree and + takes only differences between the HEAD of the submodule and the commit + recorded in the superproject into account. "untracked" will additionally + let submodules with modified tracked files in their work tree show up. + Using "none" (the default when this option is not set) also shows + submodules that have untracked files in their work tree as changed. + If this option is also present in the submodules entry in .git/config of + the superproject, the setting there will override the one found in + .gitmodules. + Both settings can be overriden on the command line by using the + "--ignore-submodule" option. + EXAMPLES -------- diff --git a/builtin/commit.c b/builtin/commit.c index 2bb30c0e80..269fa384a9 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -25,6 +25,7 @@ #include "rerere.h" #include "unpack-trees.h" #include "quote.h" +#include "submodule.h" static const char * const builtin_commit_usage[] = { "git commit [options] [--] ...", @@ -1073,6 +1074,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) status_format = STATUS_FORMAT_PORCELAIN; wt_status_prepare(&s); + gitmodules_config(); git_config(git_status_config, &s); in_merge = file_exists(git_path("MERGE_HEAD")); argc = parse_options(argc, argv, prefix, diff --git a/builtin/diff-files.c b/builtin/diff-files.c index 5b64011de8..951c7c8994 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -8,6 +8,7 @@ #include "commit.h" #include "revision.h" #include "builtin.h" +#include "submodule.h" static const char diff_files_usage[] = "git diff-files [-q] [-0/-1/2/3 |-c|--cc] [] [...]" @@ -20,6 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) unsigned options = 0; init_revisions(&rev, prefix); + gitmodules_config(); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; diff --git a/builtin/diff-index.c b/builtin/diff-index.c index 04837494fe..2eb32bd9da 100644 --- a/builtin/diff-index.c +++ b/builtin/diff-index.c @@ -3,6 +3,7 @@ #include "commit.h" #include "revision.h" #include "builtin.h" +#include "submodule.h" static const char diff_cache_usage[] = "git diff-index [-m] [--cached] " @@ -17,6 +18,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) int result; init_revisions(&rev, prefix); + gitmodules_config(); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 3c78bda566..0d2a3e9fa2 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -3,6 +3,7 @@ #include "commit.h" #include "log-tree.h" #include "builtin.h" +#include "submodule.h" static struct rev_info log_tree_opt; @@ -112,6 +113,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) int read_stdin = 0; init_revisions(opt, prefix); + gitmodules_config(); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ opt->abbrev = 0; opt->diff = 1; diff --git a/builtin/diff.c b/builtin/diff.c index 89ae89cde1..a43d326363 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -13,6 +13,7 @@ #include "revision.h" #include "log-tree.h" #include "builtin.h" +#include "submodule.h" struct blobinfo { unsigned char sha1[20]; @@ -279,6 +280,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) */ prefix = setup_git_directory_gently(&nongit); + gitmodules_config(); git_config(git_diff_ui_config, NULL); if (diff_use_color_default == -1) diff --git a/submodule.c b/submodule.c index d35a14dc06..1bcb0e90b1 100644 --- a/submodule.c +++ b/submodule.c @@ -65,6 +65,18 @@ static int submodule_config(const char *var, const char *value, void *cb) return 0; } +void gitmodules_config() +{ + const char *work_tree = get_git_work_tree(); + if (work_tree) { + struct strbuf gitmodules_path = STRBUF_INIT; + strbuf_addstr(&gitmodules_path, work_tree); + strbuf_addstr(&gitmodules_path, "/.gitmodules"); + git_config_from_file(submodule_config, gitmodules_path.buf, NULL); + strbuf_release(&gitmodules_path); + } +} + int parse_submodule_config_option(const char *var, const char *value) { int len; diff --git a/submodule.h b/submodule.h index 185a5ce6c6..8ac4037b56 100644 --- a/submodule.h +++ b/submodule.h @@ -5,6 +5,7 @@ struct diff_options; void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, const char *path); +void gitmodules_config(); int parse_submodule_config_option(const char *var, const char *value); void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *); void show_submodule_summary(FILE *f, const char *path, diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index 5022fa0b20..dccdd2348e 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -138,6 +138,32 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) git config --remove-section submodule.sub ' +test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' ' + git config --add -f .gitmodules submodule.sub.ignore none && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config -f .gitmodules submodule.sub.ignore all && + git diff HEAD >actual2 && + ! test -s actual2 && + git config -f .gitmodules submodule.sub.ignore untracked && + git diff HEAD >actual3 && + sed -e "1,/^@@/d" actual3 >actual3.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual3.body && + git config -f .gitmodules submodule.sub.ignore dirty && + git diff HEAD >actual4 && + ! test -s actual4 && + git config submodule.sub.ignore none && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config --remove-section submodule.sub && + rm .gitmodules +' + test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' ' ( cd sub && @@ -187,6 +213,25 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) git config --remove-section submodule.sub ' +test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' ' + git config --add -f .gitmodules submodule.sub.ignore all && + git diff HEAD >actual2 && + ! test -s actual2 && + git config -f .gitmodules submodule.sub.ignore untracked && + git diff HEAD >actual3 && + ! test -s actual3 && + git config -f .gitmodules submodule.sub.ignore dirty && + git diff HEAD >actual4 && + ! test -s actual4 && + git config submodule.sub.ignore none && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config --remove-section submodule.sub && + rm .gitmodules +' + test_expect_success 'git diff between submodule commits' ' git diff HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && @@ -219,6 +264,27 @@ test_expect_success 'git diff between submodule commits [.git/config]' ' git config --remove-section submodule.sub ' +test_expect_success 'git diff between submodule commits [.gitmodules]' ' + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git config --add -f .gitmodules submodule.sub.ignore dirty && + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git config -f .gitmodules submodule.sub.ignore all && + git diff HEAD^..HEAD >actual && + ! test -s actual && + git config submodule.sub.ignore dirty && + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + git config --remove-section submodule.sub && + rm .gitmodules +' + test_expect_success 'git diff (empty submodule dir)' ' : >empty && rm -rf sub/* sub/.git && diff --git a/t/t7508-status.sh b/t/t7508-status.sh index e01b2a38cd..54f9e68654 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -872,10 +872,19 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un test_cmp expect output ' +test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' ' + git config --add -f .gitmodules submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore untracked && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -884,10 +893,19 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac test_cmp expect output ' +test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' ' + git config --add -f .gitmodules submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore dirty && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -897,10 +915,19 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with modifi test_cmp expect output ' +test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' ' + git config --add -f .gitmodules submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore dirty && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -941,10 +968,19 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodules w test_cmp expect output ' +test_expect_success ".gitmodules ignore=untracked doesn't suppress submodules with modified content" ' + git config --add -f .gitmodules submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success ".git/config ignore=untracked doesn't suppress submodules with modified content" ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore untracked && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -991,10 +1027,19 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodule su test_cmp expect output ' +test_expect_success ".gitmodules ignore=untracked doesn't suppress submodule summary" ' + git config --add -f .gitmodules submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success ".git/config ignore=untracked doesn't suppress submodule summary" ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore untracked && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -1002,15 +1047,22 @@ test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summar git status --ignore-submodules=dirty > output && test_cmp expect output ' +test_expect_success ".gitmodules ignore=dirty doesn't suppress submodule summary" ' + git config --add -f .gitmodules submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary" ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore dirty && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' - cat > expect << EOF # On branch master # Changed but not updated: @@ -1037,10 +1089,19 @@ test_expect_success "--ignore-submodules=all suppresses submodule summary" ' test_cmp expect output ' +test_expect_failure '.gitmodules ignore=all suppresses submodule summary' ' + git config --add -f .gitmodules submodule.sm.ignore all && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_failure '.git/config ignore=all suppresses submodule summary' ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore all && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' From ea0869baf3277d1399baff9983239169dce704a4 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1030/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 81c8b2e172..0ec6fe9b2f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -696,11 +696,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 0722d1c88018717fcf61fa0c7993b2aceda71dd1 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1031/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From dd266d9692e681b813bdf6f7639a6771f3fd2089 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1032/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 5849d1a811704f3fd2f32c50a9a904b569339c3c Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1033/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From de5dd7b679142d5fe892b1ecd965709b3e18681a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1034/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From f7b1e98a0d850e5b1bc56a825fcfe5c87076dfa9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 5 Aug 2010 10:49:55 +0200 Subject: [PATCH 1035/3720] Add the 'diff.ignoreSubmodules' config setting When you have a lot of submodules checked out, the time penalty to check for dirty submodules can easily imply a multiplication of the total time by the factor 20. This makes the difference between almost instantaneous (< 2 seconds) and unbearably slow (> 50 seconds) here, since the disk caches are constantly overloaded. To this end, the submodule.*.ignore config option was introduced, but it is per-submodule. This commit introduces a global config setting to set a default (porcelain) value for the --ignore-submodules option, keeping the default at 'none'. It can be overridden by the submodule.*.ignore setting and by the --ignore-submodules option. Incidentally, this commit fixes an issue with the overriding logic: multiple --ignore-submodules options would not clear the previously set flags. While at it, fix a typo in the documentation for submodule.*.ignore. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 7 ++++++- diff.c | 6 +++++- submodule.c | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 5594ce04ff..8384d124c0 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -832,6 +832,11 @@ diff.renames:: will enable basic rename detection. If set to "copies" or "copy", it will detect copies, as well. +diff.ignoreSubmodules:: + Sets the default value of --ignore-submodules. Note that this + affects only 'git diff' Porcelain, and not lower level 'diff' + commands such as 'git diff-files'. + diff.suppressBlankEmpty:: A boolean to inhibit the standard behavior of printing a space before each empty output line. Defaults to false. @@ -1769,7 +1774,7 @@ submodule..ignore:: submodules that have untracked files in their work tree as changed. This setting overrides any setting made in .gitmodules for this submodule, both settings can be overriden on the command line by using the - "--ignore-submodule" option. + "--ignore-submodules" option. tar.umask:: This variable can be used to restrict the permission bits of diff --git a/diff.c b/diff.c index 8206047314..1ddfdfbc2c 100644 --- a/diff.c +++ b/diff.c @@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static int diff_no_prefix; +static struct diff_options default_diff_options; static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, @@ -107,6 +108,9 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) if (!strcmp(var, "diff.wordregex")) return git_config_string(&diff_word_regex_cfg, var, value); + if (!strcmp(var, "diff.ignoresubmodules")) + handle_ignore_submodules_arg(&default_diff_options, value); + return git_diff_basic_config(var, value, cb); } @@ -2816,7 +2820,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) void diff_setup(struct diff_options *options) { - memset(options, 0, sizeof(*options)); + memcpy(options, &default_diff_options, sizeof(*options)); memset(&diff_queued_diff, 0, sizeof(diff_queued_diff)); options->file = stdout; diff --git a/submodule.c b/submodule.c index 1bcb0e90b1..75f3368897 100644 --- a/submodule.c +++ b/submodule.c @@ -110,6 +110,10 @@ int parse_submodule_config_option(const char *var, const char *value) void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *arg) { + DIFF_OPT_CLR(diffopt, IGNORE_SUBMODULES); + DIFF_OPT_CLR(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES); + DIFF_OPT_CLR(diffopt, IGNORE_DIRTY_SUBMODULES); + if (!strcmp(arg, "all")) DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES); else if (!strcmp(arg, "untracked")) From 4c0ebae3b5d53953d7c8a255409f4f2c6d7f5c32 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 10 Aug 2010 00:22:27 +0200 Subject: [PATCH 1036/3720] Configure ignore option for submodule name instead of path Signed-off-by: Jens Lehmann Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 2 +- submodule.c | 45 ++++++++++------ t/t4027-diff-submodule.sh | 67 ++++++++++++++---------- t/t7508-status.sh | 105 +++++++++++++++++++++++--------------- 4 files changed, 133 insertions(+), 86 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 8384d124c0..470fd9323a 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1763,7 +1763,7 @@ submodule..update:: URL and other values found in the `.gitmodules` file. See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. -submodule..ignore:: +submodule..ignore:: Defines under what circumstances "git status" and the diff family show a submodule as modified. When set to "all", it will never be considered modified, "dirty" will ignore all changes to the submodules work tree and diff --git a/submodule.c b/submodule.c index 75f3368897..beb8622317 100644 --- a/submodule.c +++ b/submodule.c @@ -8,7 +8,8 @@ #include "diffcore.h" #include "string-list.h" -struct string_list config_ignore; +struct string_list config_name_for_path; +struct string_list config_ignore_for_name; static int add_submodule_odb(const char *path) { @@ -52,10 +53,13 @@ done: void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, const char *path) { - struct string_list_item *ignore_option; - ignore_option = unsorted_string_list_lookup(&config_ignore, path); - if (ignore_option) - handle_ignore_submodules_arg(diffopt, ignore_option->util); + struct string_list_item *path_option, *ignore_option; + path_option = unsorted_string_list_lookup(&config_name_for_path, path); + if (path_option) { + ignore_option = unsorted_string_list_lookup(&config_ignore_for_name, path_option->util); + if (ignore_option) + handle_ignore_submodules_arg(diffopt, ignore_option->util); + } } static int submodule_config(const char *var, const char *value, void *cb) @@ -80,28 +84,37 @@ void gitmodules_config() int parse_submodule_config_option(const char *var, const char *value) { int len; - struct string_list_item *ignore_option; - struct strbuf path = STRBUF_INIT; + struct string_list_item *config; + struct strbuf submodname = STRBUF_INIT; var += 10; /* Skip "submodule." */ len = strlen(var); - if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { + if ((len > 5) && !strcmp(var + len - 5, ".path")) { + strbuf_add(&submodname, var, len - 5); + config = unsorted_string_list_lookup(&config_name_for_path, value); + if (config) + free(config->util); + else + config = string_list_append(&config_name_for_path, xstrdup(value)); + config->util = strbuf_detach(&submodname, NULL); + strbuf_release(&submodname); + } else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { if (strcmp(value, "untracked") && strcmp(value, "dirty") && strcmp(value, "all") && strcmp(value, "none")) { warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var); return 0; } - strbuf_add(&path, var, len - 7); - ignore_option = unsorted_string_list_lookup(&config_ignore, path.buf); - if (ignore_option) - free(ignore_option->util); + strbuf_add(&submodname, var, len - 7); + config = unsorted_string_list_lookup(&config_ignore_for_name, submodname.buf); + if (config) + free(config->util); else - ignore_option = string_list_append(&config_ignore, - strbuf_detach(&path, NULL)); - strbuf_release(&path); - ignore_option->util = xstrdup(value); + config = string_list_append(&config_ignore_for_name, + strbuf_detach(&submodname, NULL)); + strbuf_release(&submodname); + config->util = xstrdup(value); return 0; } return 0; diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index dccdd2348e..1bc6e77a0d 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -115,52 +115,57 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)' ' test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.git/config]' ' - git config submodule.sub.ignore none && + git config submodule.subname.ignore none && + git config submodule.subname.path sub && git diff HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config submodule.sub.ignore all && + git config submodule.subname.ignore all && git diff HEAD >actual2 && ! test -s actual2 && - git config submodule.sub.ignore untracked && + git config submodule.subname.ignore untracked && git diff HEAD >actual3 && sed -e "1,/^@@/d" actual3 >actual3.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual3.body && - git config submodule.sub.ignore dirty && + git config submodule.subname.ignore dirty && git diff HEAD >actual4 && ! test -s actual4 && git diff HEAD --ignore-submodules=none >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config --remove-section submodule.sub + git config --remove-section submodule.subname ' test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' ' - git config --add -f .gitmodules submodule.sub.ignore none && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sub && git diff HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config -f .gitmodules submodule.sub.ignore all && + git config -f .gitmodules submodule.subname.ignore all && + git config -f .gitmodules submodule.subname.path sub && git diff HEAD >actual2 && ! test -s actual2 && - git config -f .gitmodules submodule.sub.ignore untracked && + git config -f .gitmodules submodule.subname.ignore untracked && git diff HEAD >actual3 && sed -e "1,/^@@/d" actual3 >actual3.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual3.body && - git config -f .gitmodules submodule.sub.ignore dirty && + git config -f .gitmodules submodule.subname.ignore dirty && git diff HEAD >actual4 && ! test -s actual4 && - git config submodule.sub.ignore none && + git config submodule.subname.ignore none && + git config submodule.subname.path sub && git diff HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config --remove-section submodule.sub && + git config --remove-section submodule.subname && + git config --remove-section -f .gitmodules submodule.subname && rm .gitmodules ' @@ -197,38 +202,42 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)' ' test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.git/config]' ' - git config submodule.sub.ignore all && + git config submodule.subname.ignore all && + git config submodule.subname.path sub && git diff HEAD >actual2 && ! test -s actual2 && - git config submodule.sub.ignore untracked && + git config submodule.subname.ignore untracked && git diff HEAD >actual3 && ! test -s actual3 && - git config submodule.sub.ignore dirty && + git config submodule.subname.ignore dirty && git diff HEAD >actual4 && ! test -s actual4 && git diff --ignore-submodules=none HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config --remove-section submodule.sub + git config --remove-section submodule.subname ' test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' ' - git config --add -f .gitmodules submodule.sub.ignore all && + git config --add -f .gitmodules submodule.subname.ignore all && + git config --add -f .gitmodules submodule.subname.path sub && git diff HEAD >actual2 && ! test -s actual2 && - git config -f .gitmodules submodule.sub.ignore untracked && + git config -f .gitmodules submodule.subname.ignore untracked && git diff HEAD >actual3 && ! test -s actual3 && - git config -f .gitmodules submodule.sub.ignore dirty && + git config -f .gitmodules submodule.subname.ignore dirty && git diff HEAD >actual4 && ! test -s actual4 && - git config submodule.sub.ignore none && + git config submodule.subname.ignore none && + git config submodule.subname.path sub && git diff HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config --remove-section submodule.sub && + git config --remove-section submodule.subname && + git config --remove-section -f .gitmodules submodule.subname && rm .gitmodules ' @@ -250,18 +259,19 @@ test_expect_success 'git diff between submodule commits [.git/config]' ' sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && test_cmp expect.body actual.body && - git config submodule.sub.ignore dirty && + git config submodule.subname.ignore dirty && + git config submodule.subname.path sub && git diff HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && test_cmp expect.body actual.body && - git config submodule.sub.ignore all && + git config submodule.subname.ignore all && git diff HEAD^..HEAD >actual && ! test -s actual && git diff --ignore-submodules=dirty HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && - git config --remove-section submodule.sub + git config --remove-section submodule.subname ' test_expect_success 'git diff between submodule commits [.gitmodules]' ' @@ -269,19 +279,22 @@ test_expect_success 'git diff between submodule commits [.gitmodules]' ' sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && test_cmp expect.body actual.body && - git config --add -f .gitmodules submodule.sub.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore dirty && + git config --add -f .gitmodules submodule.subname.path sub && git diff HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && test_cmp expect.body actual.body && - git config -f .gitmodules submodule.sub.ignore all && + git config -f .gitmodules submodule.subname.ignore all && git diff HEAD^..HEAD >actual && ! test -s actual && - git config submodule.sub.ignore dirty && + git config submodule.subname.ignore dirty && + git config submodule.subname.path sub && git diff HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && - git config --remove-section submodule.sub && + git config --remove-section submodule.subname && + git config --remove-section -f .gitmodules submodule.subname && rm .gitmodules ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 54f9e68654..1b92845be8 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -873,19 +873,22 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un ' test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' ' - git config --add -f .gitmodules submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore untracked && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore untracked && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config --remove-section -f .gitmodules submodule.subname ' test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' ' @@ -894,19 +897,22 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac ' test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' ' - git config --add -f .gitmodules submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore dirty && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore dirty && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' ' @@ -916,19 +922,22 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with modifi ' test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' ' - git config --add -f .gitmodules submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore dirty && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore dirty && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' cat > expect << EOF @@ -969,19 +978,22 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodules w ' test_expect_success ".gitmodules ignore=untracked doesn't suppress submodules with modified content" ' - git config --add -f .gitmodules submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore untracked && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success ".git/config ignore=untracked doesn't suppress submodules with modified content" ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore untracked && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' head2=$(cd sm && git commit -q -m "2nd commit" foo && git rev-parse --short=7 --verify HEAD) @@ -1028,19 +1040,22 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodule su ' test_expect_success ".gitmodules ignore=untracked doesn't suppress submodule summary" ' - git config --add -f .gitmodules submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore untracked && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success ".git/config ignore=untracked doesn't suppress submodule summary" ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore untracked && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summary" ' @@ -1048,19 +1063,22 @@ test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summar test_cmp expect output ' test_expect_success ".gitmodules ignore=dirty doesn't suppress submodule summary" ' - git config --add -f .gitmodules submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore dirty && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary" ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore dirty && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' cat > expect << EOF @@ -1090,19 +1108,22 @@ test_expect_success "--ignore-submodules=all suppresses submodule summary" ' ' test_expect_failure '.gitmodules ignore=all suppresses submodule summary' ' - git config --add -f .gitmodules submodule.sm.ignore all && + git config --add -f .gitmodules submodule.subname.ignore all && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_failure '.git/config ignore=all suppresses submodule summary' ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore all && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore all && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' test_done From b4dfb677ae8efc0cc30fdb45bbc565056924c41a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Aug 2010 12:04:40 +0200 Subject: [PATCH 1037/3720] Fix typo in pack-objects' usage Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0e81673118..3756cf36ee 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -30,7 +30,7 @@ static const char pack_usage[] = " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n" " [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n" " [--reflog] [--stdout | base-name] [--include-tag]\n" - " [--keep-unreachable | --unpack-unreachable \n" + " [--keep-unreachable | --unpack-unreachable]\n" " [ Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 1038/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index e151516532..4228af6659 100644 --- a/Makefile +++ b/Makefile @@ -1925,6 +1925,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1932,6 +1933,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 99e55e13839de05d59e98bbf20552e00678493d8 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 1039/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 6744b4ceb1f1f3a959c791697a1138a8155f9409 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1040/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 834d166e5a0c34ac36934738ea77126cf49f35cb Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1041/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f81fb918da..c3b78d6d4d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index c9fa3df7f5..eaf6375bf5 100644 --- a/cache.h +++ b/cache.h @@ -552,6 +552,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 9a8e336582..8d3f5adac8 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index cdcf5836c6..42e94f991b 100644 --- a/config.c +++ b/config.c @@ -595,6 +595,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 83d38d3c23..ee3243c3d6 100644 --- a/environment.c +++ b/environment.c @@ -53,6 +53,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 02a73eeb66..836a8df41f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -503,4 +503,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From f1560253dc23fc647da65a0aefbf2d83fb1dd5d1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1042/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 8d3f5adac8..72f6d57465 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From a0a50f6f30c2ddd2a86ea68de7ff21693a88ada1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1043/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 3c4c6ec27099d09bea3dd105f8341f33489bed25 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 1044/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..1eaa83f686 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NONMINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NONMINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/test-lib.sh b/t/test-lib.sh index e8f21d577c..380b84b991 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -877,6 +877,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From cc7d0bed20db956737fcb4287510a07d4435499e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1045/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index bb104895a9..76981e563d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1213,9 +1213,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2015,7 +2012,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2027,12 +2024,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2053,18 +2057,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2085,20 +2086,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 8e04d91a76fe15c57cb99b4ffd0aedc678a93f9d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1046/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 72f6d57465..4b2f154b0f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From c4ade8372ab694d5dda4f3bfb715ddc5afb78168 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1047/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b2f154b0f..d1dc71f563 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1243,7 +1259,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From ef3ad5023aab2d8438c6eef53a9d6a02b27d90ca Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1048/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d1dc71f563..04d6d44676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1300,6 +1353,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From b8cd9c08a6405ca1f52e28b1e0c90a0205833e7f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1049/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 04d6d44676..8839ed52d5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 28b251c0356aaa814c4913a5a45bfd5e0706c382 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1050/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 76981e563d..ccbed506ad 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From dfb752255388ef8c7c61b7d0814dd12119d4dadd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1051/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From ad3bd3124ac35dc69470708bb4920c0e4e34d030 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1052/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8839ed52d5..38cb773315 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 6a9224c1912be83840777e0717225f8d8e34f2bf Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1053/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 38cb773315..ee1fc7d1fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1585,6 +1585,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1594,9 +1595,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 7dc405a3fe3e8797870ce575e0aea66ad54917c8 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1054/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7c0a698b92..56fc26e13d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -324,4 +324,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 380b84b991..f59b34a824 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -872,6 +872,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 033e7f25c5107241a2fdeb217434f3f75713cee5 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1055/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ee1fc7d1fa..e3a151ffd4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 206319f5ffe39ca76d9b2fa4161cf39c8bffdca1 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 1056/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e3a151ffd4..4fe094f676 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 2613d5a48a0822e8d79a68c2de5f8fb4675e7c32 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 1057/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..6b9f76a27d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 6167cce54ecb294d93cfe0a018a708c6598d35fb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1058/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a72fe3ae64..2e210faf3c 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From a0a91714c28d1fdb85815f22d489c1097976f202 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1059/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c3b78d6d4d..29a3c7f008 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1576,6 +1576,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index d634b5a3d5..21974a0eb8 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From d7696b8a1b0adbee19e2e0a191f7dbfe6ab0a075 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1060/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4fe094f676..3b8107372f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 94a9dfa9b47a891c68f9ea09e203f58a0e66b192 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1061/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 6dab3bf6a7..53f89d6cd2 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1017,7 +1017,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 31a12dd6dbe248013e53037ee0d458476f1c8cc7 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1062/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 53f89d6cd2..e157e4b469 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1103,7 +1103,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 967228d3d46f6f03810375f1a83923496b5ab4a0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1063/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3b8107372f..fe13ecdfdb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 1be191d626cb7032bfdbafb7bcb95a1b2e2d22a5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1064/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index f3d1660d02..902a9f9c21 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index fe13ecdfdb..4a83c617f4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1726,3 +1726,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 42e94f991b..1d2410e512 100644 --- a/config.c +++ b/config.c @@ -804,7 +804,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 836a8df41f..1df461f256 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -507,4 +507,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 6b23023095..6345b23876 100644 --- a/path.c +++ b/path.c @@ -315,7 +315,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 14ce37f2e8f30b9fc384b160fe6dc9e0e64a3bae Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:42:31 +0200 Subject: [PATCH 1065/3720] Ignore a gitweb-specific file Signed-off-by: Johannes Schindelin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 14e2b6bde9..a5529c426e 100644 --- a/.gitignore +++ b/.gitignore @@ -159,6 +159,7 @@ /gitweb/GITWEB-BUILD-OPTIONS /gitweb/gitweb.cgi /gitweb/gitweb.min.* +/gitweb/GITWEB-BUILD-OPTIONS /test-chmtime /test-ctype /test-date From fe2f1ccefde5d4cffe07f2f89bb8e53a69413c60 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1066/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index f59b34a824..2e6b516586 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -775,6 +775,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . ../GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 2ac4fa860661b03d033e198d6c083796e00ff23e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1067/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From b6f9accaa9d0ec89fe6595e831f26b0f3978dd87 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1068/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From 4035e2199f67437a30f341888515166b64ee8b9a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1069/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6b9f76a27d..ae9fc2346d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From c9771e79c3b45c65883efb283b76d9d310cce6e2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1070/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 2e6b516586..f3c2a45f43 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From f5d86830d1a316401171745bde0246ecb71bad14 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1071/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From bf5d632c4defea93043dcf88bc2dc416b0e95bc9 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1072/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index eaf6375bf5..59886c0a8b 100644 --- a/cache.h +++ b/cache.h @@ -718,7 +718,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index 4a83c617f4..861d3dad35 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1744,3 +1744,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 1df461f256..8239679b32 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -179,6 +179,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 6345b23876..3870b2411a 100644 --- a/path.c +++ b/path.c @@ -730,10 +730,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From fbb9dffb637419124651fb1b445d57f279e299ad Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1073/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 902a9f9c21..8b5069f712 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 7ee779d156ebc3302db44afdad068dcc4d14c379 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1074/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 861d3dad35..81c8b2e172 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1747,23 +1747,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From bfd9f9f9fc6d61cf02062863677aa29a099e510b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 17:40:44 +0200 Subject: [PATCH 1075/3720] Make sure that git_getpass() never returns NULL The result of git_getpass() is used without checking for NULL, so let's just die() instead of returning NULL. Signed-off-by: Johannes Schindelin --- connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 02e738a014..d3e967fcd9 100644 --- a/connect.c +++ b/connect.c @@ -628,8 +628,12 @@ char *git_getpass(const char *prompt) askpass = getenv("GIT_ASKPASS"); - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; From 30a2f200654600e0758c81aba91db769fe3c7b72 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1076/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ccbed506ad..8eeebe06e2 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 089d101e0dd66f420479b6f9c92fcd338855da1e Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1077/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From b1a201bc560a858da9f6bf331a56de5bf382a1ea Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Mon, 26 Jul 2010 20:27:50 +0200 Subject: [PATCH 1078/3720] Submodules: Add the new "ignore" config option for diff and status The new "ignore" config option controls the default behavior for "git status" and the diff family. It specifies under what circumstances they consider submodules as modified and can be set separately for each submodule. The command line option "--ignore-submodules=" has been extended to accept the new parameter "none" for both status and diff. Users that chose submodules to get rid of long work tree scanning times might want to set the "dirty" option for those submodules. This brings back the pre 1.7.0 behavior, where submodule work trees were never scanned for modifications. By using "--ignore-submodules=none" on the command line the status and diff commands can be told to do a full scan. This option can be set to the following values (which have the same name and meaning as for the "--ignore-submodules" option of status and diff): "all": All changes to the submodule will be ignored. "dirty": Only differences of the commit recorded in the superproject and the submodules HEAD will be considered modifications, all changes to the work tree of the submodule will be ignored. When using this value, the submodule will not be scanned for work tree changes at all, leading to a performance benefit on large submodules. "untracked": Only untracked files in the submodules work tree are ignored, a changed HEAD and/or modified files in the submodule will mark it as modified. "none" (which is the default): Either untracked or modified files in a submodules work tree or a difference between the subdmodules HEAD and the commit recorded in the superproject will make it show up as changed. This value is added as a new parameter for the "--ignore-submodules" option of the diff family and "git status" so the user can override the settings in the configuration. Signed-off-by: Jens Lehmann Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 10 ++++ Documentation/diff-options.txt | 6 ++- Documentation/git-status.txt | 6 ++- diff-lib.c | 15 ++++-- diff.c | 35 ++++++++++--- diff.h | 1 + submodule.c | 51 ++++++++++++++++++- submodule.h | 3 ++ t/t4027-diff-submodule.sh | 73 ++++++++++++++++++++++++++ t/t7508-status.sh | 93 ++++++++++++++++++++++++++++++++-- wt-status.c | 8 ++- 11 files changed, 281 insertions(+), 20 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 29a3c7f008..b03ee4b087 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1758,6 +1758,16 @@ submodule..update:: URL and other values found in the `.gitmodules` file. See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. +submodule..ignore:: + Defines under what circumstances "git status" and the diff family show + a submodule as modified. When set to "all", it will never be considered + modified, "dirty" will ignore all changes to the submodules work tree and + takes only differences between the HEAD of the submodule and the commit + recorded in the superproject into account. "untracked" will additionally + let submodules with modified tracked files in their work tree show up. + Using "none" (the default when this option is not set) also shows + submodules that have untracked files in their work tree as changed. + tar.umask:: This variable can be used to restrict the permission bits of tar archive entries. The default is 0002, which turns off the diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index eecedaab6e..29f8b0f7f1 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -355,7 +355,11 @@ endif::git-format-patch[] --ignore-submodules[=]:: Ignore changes to submodules in the diff generation. can be - either "untracked", "dirty" or "all", which is the default. When + either "none", "untracked", "dirty" or "all", which is the default + Using "none" will consider the submodule modified when it either contains + untracked or modified files or its HEAD differs from the commit recorded + in the superproject and can be used to override any settings of the + 'ignore' option in linkgit:git-config[1]. When "untracked" is used submodules are not considered dirty when they only contain untracked content (but they are still scanned for modified content). Using "dirty" ignores all changes to the work tree of submodules, diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index 2fd054c104..a7a5d79416 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -55,7 +55,11 @@ specified. --ignore-submodules[=]:: Ignore changes to submodules when looking for changes. can be - either "untracked", "dirty" or "all", which is the default. When + either "none", "untracked", "dirty" or "all", which is the default. + Using "none" will consider the submodule modified when it either contains + untracked or modified files or its HEAD differs from the commit recorded + in the superproject and can be used to override any settings of the + 'ignore' option in linkgit:git-config[1]. When "untracked" is used submodules are not considered dirty when they only contain untracked content (but they are still scanned for modified content). Using "dirty" ignores all changes to the work tree of submodules, diff --git a/diff-lib.c b/diff-lib.c index 8b8978ae6d..392ce2bef0 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -68,11 +68,16 @@ static int match_stat_with_submodule(struct diff_options *diffopt, unsigned ce_option, unsigned *dirty_submodule) { int changed = ce_match_stat(ce, st, ce_option); - if (S_ISGITLINK(ce->ce_mode) - && !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES) - && !DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES) - && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES))) { - *dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES)); + if (S_ISGITLINK(ce->ce_mode)) { + unsigned orig_flags = diffopt->flags; + if (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG)) + set_diffopt_flags_from_submodule_config(diffopt, ce->name); + if (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)) + changed = 0; + else if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES) + && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES))) + *dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES)); + diffopt->flags = orig_flags; } return changed; } diff --git a/diff.c b/diff.c index 782896db55..bf6b9b129c 100644 --- a/diff.c +++ b/diff.c @@ -141,6 +141,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } + if (!prefixcmp(var, "submodule.")) + return parse_submodule_config_option(var, value); + return git_color_default_config(var, value, cb); } @@ -3165,11 +3168,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_SET(options, ALLOW_TEXTCONV); else if (!strcmp(arg, "--no-textconv")) DIFF_OPT_CLR(options, ALLOW_TEXTCONV); - else if (!strcmp(arg, "--ignore-submodules")) + else if (!strcmp(arg, "--ignore-submodules")) { + DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(options, "all"); - else if (!prefixcmp(arg, "--ignore-submodules=")) + } else if (!prefixcmp(arg, "--ignore-submodules=")) { + DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(options, arg + 20); - else if (!strcmp(arg, "--submodule")) + } else if (!strcmp(arg, "--submodule")) DIFF_OPT_SET(options, SUBMODULE_LOG); else if (!prefixcmp(arg, "--submodule=")) { if (!strcmp(arg + 12, "log")) @@ -4102,6 +4107,24 @@ int diff_result_code(struct diff_options *opt, int status) return result; } +/* + * Shall changes to this submodule be ignored? + * + * Submodule changes can be configured to be ignored separately for each path, + * but that configuration can be overridden from the command line. + */ +static int is_submodule_ignored(const char *path, struct diff_options *options) +{ + int ignored = 0; + unsigned orig_flags = options->flags; + if (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG)) + set_diffopt_flags_from_submodule_config(options, path); + if (DIFF_OPT_TST(options, IGNORE_SUBMODULES)) + ignored = 1; + options->flags = orig_flags; + return ignored; +} + void diff_addremove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, @@ -4109,7 +4132,7 @@ void diff_addremove(struct diff_options *options, { struct diff_filespec *one, *two; - if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(mode)) + if (S_ISGITLINK(mode) && is_submodule_ignored(concatpath, options)) return; /* This may look odd, but it is a preparation for @@ -4156,8 +4179,8 @@ void diff_change(struct diff_options *options, { struct diff_filespec *one, *two; - if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(old_mode) - && S_ISGITLINK(new_mode)) + if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) && + is_submodule_ignored(concatpath, options)) return; if (DIFF_OPT_TST(options, REVERSE_DIFF)) { diff --git a/diff.h b/diff.h index 063d10ac22..53ad345469 100644 --- a/diff.h +++ b/diff.h @@ -77,6 +77,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data) #define DIFF_OPT_DIRTY_SUBMODULES (1 << 24) #define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25) #define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26) +#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) diff --git a/submodule.c b/submodule.c index 61cb6e21dd..d35a14dc06 100644 --- a/submodule.c +++ b/submodule.c @@ -6,6 +6,9 @@ #include "revision.h" #include "run-command.h" #include "diffcore.h" +#include "string-list.h" + +struct string_list config_ignore; static int add_submodule_odb(const char *path) { @@ -46,6 +49,52 @@ done: return ret; } +void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, + const char *path) +{ + struct string_list_item *ignore_option; + ignore_option = unsorted_string_list_lookup(&config_ignore, path); + if (ignore_option) + handle_ignore_submodules_arg(diffopt, ignore_option->util); +} + +static int submodule_config(const char *var, const char *value, void *cb) +{ + if (!prefixcmp(var, "submodule.")) + return parse_submodule_config_option(var, value); + return 0; +} + +int parse_submodule_config_option(const char *var, const char *value) +{ + int len; + struct string_list_item *ignore_option; + struct strbuf path = STRBUF_INIT; + + var += 10; /* Skip "submodule." */ + + len = strlen(var); + if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { + if (strcmp(value, "untracked") && strcmp(value, "dirty") && + strcmp(value, "all") && strcmp(value, "none")) { + warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var); + return 0; + } + + strbuf_add(&path, var, len - 7); + ignore_option = unsorted_string_list_lookup(&config_ignore, path.buf); + if (ignore_option) + free(ignore_option->util); + else + ignore_option = string_list_append(&config_ignore, + strbuf_detach(&path, NULL)); + strbuf_release(&path); + ignore_option->util = xstrdup(value); + return 0; + } + return 0; +} + void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *arg) { @@ -55,7 +104,7 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt, DIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES); else if (!strcmp(arg, "dirty")) DIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES); - else + else if (strcmp(arg, "none")) die("bad --ignore-submodules argument: %s", arg); } diff --git a/submodule.h b/submodule.h index 6fd3bb4070..185a5ce6c6 100644 --- a/submodule.h +++ b/submodule.h @@ -3,6 +3,9 @@ struct diff_options; +void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, + const char *path); +int parse_submodule_config_option(const char *var, const char *value); void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *); void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index 1bd8e5ee3a..5022fa0b20 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -114,6 +114,30 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)' ! test -s actual4 ' +test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.git/config]' ' + git config submodule.sub.ignore none && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config submodule.sub.ignore all && + git diff HEAD >actual2 && + ! test -s actual2 && + git config submodule.sub.ignore untracked && + git diff HEAD >actual3 && + sed -e "1,/^@@/d" actual3 >actual3.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual3.body && + git config submodule.sub.ignore dirty && + git diff HEAD >actual4 && + ! test -s actual4 && + git diff HEAD --ignore-submodules=none >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config --remove-section submodule.sub +' + test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' ' ( cd sub && @@ -146,6 +170,55 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)' ! test -s actual4 ' +test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.git/config]' ' + git config submodule.sub.ignore all && + git diff HEAD >actual2 && + ! test -s actual2 && + git config submodule.sub.ignore untracked && + git diff HEAD >actual3 && + ! test -s actual3 && + git config submodule.sub.ignore dirty && + git diff HEAD >actual4 && + ! test -s actual4 && + git diff --ignore-submodules=none HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config --remove-section submodule.sub +' + +test_expect_success 'git diff between submodule commits' ' + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git diff --ignore-submodules=dirty HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git diff --ignore-submodules HEAD^..HEAD >actual && + ! test -s actual +' + +test_expect_success 'git diff between submodule commits [.git/config]' ' + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git config submodule.sub.ignore dirty && + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git config submodule.sub.ignore all && + git diff HEAD^..HEAD >actual && + ! test -s actual && + git diff --ignore-submodules=dirty HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + git config --remove-section submodule.sub +' + test_expect_success 'git diff (empty submodule dir)' ' : >empty && rm -rf sub/* sub/.git && diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 2e210faf3c..e01b2a38cd 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -832,24 +832,38 @@ test_expect_success POSIXPERM 'status succeeds in a read-only repository' ' (exit $status) ' +(cd sm && echo > bar && git add bar && git commit -q -m 'Add bar' && cd .. && git add sm) +new_head=$(cd sm && git rev-parse --short=7 --verify HEAD) +touch .gitmodules + cat > expect << EOF # On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# modified: sm +# # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # modified: dir1/modified # +# Submodule changes to be committed: +# +# * sm $head...$new_head (1): +# > Add bar +# # Untracked files: # (use "git add ..." to include in what will be committed) # +# .gitmodules # dir1/untracked # dir2/modified # dir2/untracked # expect # output # untracked -no changes added to commit (use "git add" and/or "git commit -a") EOF test_expect_success '--ignore-submodules=untracked suppresses submodules with untracked content' ' @@ -858,19 +872,45 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un test_cmp expect output ' +test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' ' + git config --add submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' ' git status --ignore-submodules=dirty > output && test_cmp expect output ' +test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' ' + git config --add submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' ' echo modified > sm/foo && git status --ignore-submodules=dirty > output && test_cmp expect output ' +test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' ' + git config --add submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + cat > expect << EOF # On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# modified: sm +# # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) @@ -879,16 +919,21 @@ cat > expect << EOF # modified: dir1/modified # modified: sm (modified content) # +# Submodule changes to be committed: +# +# * sm $head...$new_head (1): +# > Add bar +# # Untracked files: # (use "git add ..." to include in what will be committed) # +# .gitmodules # dir1/untracked # dir2/modified # dir2/untracked # expect # output # untracked -no changes added to commit (use "git add" and/or "git commit -a") EOF test_expect_success "--ignore-submodules=untracked doesn't suppress submodules with modified content" ' @@ -896,10 +941,22 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodules w test_cmp expect output ' +test_expect_success ".git/config ignore=untracked doesn't suppress submodules with modified content" ' + git config --add submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + head2=$(cd sm && git commit -q -m "2nd commit" foo && git rev-parse --short=7 --verify HEAD) cat > expect << EOF # On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# modified: sm +# # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) @@ -907,21 +964,26 @@ cat > expect << EOF # modified: dir1/modified # modified: sm (new commits) # +# Submodule changes to be committed: +# +# * sm $head...$new_head (1): +# > Add bar +# # Submodules changed but not updated: # -# * sm $head...$head2 (1): +# * sm $new_head...$head2 (1): # > 2nd commit # # Untracked files: # (use "git add ..." to include in what will be committed) # +# .gitmodules # dir1/untracked # dir2/modified # dir2/untracked # expect # output # untracked -no changes added to commit (use "git add" and/or "git commit -a") EOF test_expect_success "--ignore-submodules=untracked doesn't suppress submodule summary" ' @@ -929,11 +991,26 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodule su test_cmp expect output ' +test_expect_success ".git/config ignore=untracked doesn't suppress submodule summary" ' + git config --add submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summary" ' git status --ignore-submodules=dirty > output && test_cmp expect output ' +test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary" ' + git config --add submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + + cat > expect << EOF # On branch master # Changed but not updated: @@ -945,6 +1022,7 @@ cat > expect << EOF # Untracked files: # (use "git add ..." to include in what will be committed) # +# .gitmodules # dir1/untracked # dir2/modified # dir2/untracked @@ -959,4 +1037,11 @@ test_expect_success "--ignore-submodules=all suppresses submodule summary" ' test_cmp expect output ' +test_expect_failure '.git/config ignore=all suppresses submodule summary' ' + git config --add submodule.sm.ignore all && + git status > output && + test_cmp expect output && + git config --remove-section submodule.sm +' + test_done diff --git a/wt-status.c b/wt-status.c index 2f9e33c8fa..54b6b03b9c 100644 --- a/wt-status.c +++ b/wt-status.c @@ -313,8 +313,10 @@ static void wt_status_collect_changes_worktree(struct wt_status *s) DIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES); if (!s->show_untracked_files) DIFF_OPT_SET(&rev.diffopt, IGNORE_UNTRACKED_IN_SUBMODULES); - if (s->ignore_submodule_arg) + if (s->ignore_submodule_arg) { + DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg); + } rev.diffopt.format_callback = wt_status_collect_changed_cb; rev.diffopt.format_callback_data = s; rev.prune_data = s->pathspec; @@ -331,8 +333,10 @@ static void wt_status_collect_changes_index(struct wt_status *s) opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference; setup_revisions(0, NULL, &rev, &opt); - if (s->ignore_submodule_arg) + if (s->ignore_submodule_arg) { + DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg); + } rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = wt_status_collect_updated_cb; From 3ea82c9f1cede89b6e30b1fe4202ad3c2278d03b Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Mon, 26 Jul 2010 20:28:31 +0200 Subject: [PATCH 1079/3720] Submodules: Use "ignore" settings from .gitmodules too for diff and status The .gitmodules file is parsed for "submodule..ignore" entries before looking for them in .git/config. Thus settings found in .git/config will override those from .gitmodules, thereby allowing the local developer to ignore settings given by the remote side while also letting upstream set defaults for those users who don't have special needs. Signed-off-by: Jens Lehmann Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 3 ++ Documentation/diff-options.txt | 2 +- Documentation/git-status.txt | 2 +- Documentation/gitmodules.txt | 15 ++++++++ builtin/commit.c | 2 ++ builtin/diff-files.c | 2 ++ builtin/diff-index.c | 2 ++ builtin/diff-tree.c | 2 ++ builtin/diff.c | 2 ++ submodule.c | 12 +++++++ submodule.h | 1 + t/t4027-diff-submodule.sh | 66 ++++++++++++++++++++++++++++++++++ t/t7508-status.sh | 63 +++++++++++++++++++++++++++++++- 13 files changed, 171 insertions(+), 3 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index b03ee4b087..5594ce04ff 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1767,6 +1767,9 @@ submodule..ignore:: let submodules with modified tracked files in their work tree show up. Using "none" (the default when this option is not set) also shows submodules that have untracked files in their work tree as changed. + This setting overrides any setting made in .gitmodules for this submodule, + both settings can be overriden on the command line by using the + "--ignore-submodule" option. tar.umask:: This variable can be used to restrict the permission bits of diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 29f8b0f7f1..4656a97e60 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -359,7 +359,7 @@ endif::git-format-patch[] Using "none" will consider the submodule modified when it either contains untracked or modified files or its HEAD differs from the commit recorded in the superproject and can be used to override any settings of the - 'ignore' option in linkgit:git-config[1]. When + 'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When "untracked" is used submodules are not considered dirty when they only contain untracked content (but they are still scanned for modified content). Using "dirty" ignores all changes to the work tree of submodules, diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index a7a5d79416..dae190a5f2 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -59,7 +59,7 @@ specified. Using "none" will consider the submodule modified when it either contains untracked or modified files or its HEAD differs from the commit recorded in the superproject and can be used to override any settings of the - 'ignore' option in linkgit:git-config[1]. When + 'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When "untracked" is used submodules are not considered dirty when they only contain untracked content (but they are still scanned for modified content). Using "dirty" ignores all changes to the work tree of submodules, diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index 72a13d18e0..8ae107da25 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -44,6 +44,21 @@ submodule..update:: This config option is overridden if 'git submodule update' is given the '--merge' or '--rebase' options. +submodule..ignore:: + Defines under what circumstances "git status" and the diff family show + a submodule as modified. When set to "all", it will never be considered + modified, "dirty" will ignore all changes to the submodules work tree and + takes only differences between the HEAD of the submodule and the commit + recorded in the superproject into account. "untracked" will additionally + let submodules with modified tracked files in their work tree show up. + Using "none" (the default when this option is not set) also shows + submodules that have untracked files in their work tree as changed. + If this option is also present in the submodules entry in .git/config of + the superproject, the setting there will override the one found in + .gitmodules. + Both settings can be overriden on the command line by using the + "--ignore-submodule" option. + EXAMPLES -------- diff --git a/builtin/commit.c b/builtin/commit.c index 2bb30c0e80..269fa384a9 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -25,6 +25,7 @@ #include "rerere.h" #include "unpack-trees.h" #include "quote.h" +#include "submodule.h" static const char * const builtin_commit_usage[] = { "git commit [options] [--] ...", @@ -1073,6 +1074,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) status_format = STATUS_FORMAT_PORCELAIN; wt_status_prepare(&s); + gitmodules_config(); git_config(git_status_config, &s); in_merge = file_exists(git_path("MERGE_HEAD")); argc = parse_options(argc, argv, prefix, diff --git a/builtin/diff-files.c b/builtin/diff-files.c index 5b64011de8..951c7c8994 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -8,6 +8,7 @@ #include "commit.h" #include "revision.h" #include "builtin.h" +#include "submodule.h" static const char diff_files_usage[] = "git diff-files [-q] [-0/-1/2/3 |-c|--cc] [] [...]" @@ -20,6 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) unsigned options = 0; init_revisions(&rev, prefix); + gitmodules_config(); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; diff --git a/builtin/diff-index.c b/builtin/diff-index.c index 04837494fe..2eb32bd9da 100644 --- a/builtin/diff-index.c +++ b/builtin/diff-index.c @@ -3,6 +3,7 @@ #include "commit.h" #include "revision.h" #include "builtin.h" +#include "submodule.h" static const char diff_cache_usage[] = "git diff-index [-m] [--cached] " @@ -17,6 +18,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) int result; init_revisions(&rev, prefix); + gitmodules_config(); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 3c78bda566..0d2a3e9fa2 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -3,6 +3,7 @@ #include "commit.h" #include "log-tree.h" #include "builtin.h" +#include "submodule.h" static struct rev_info log_tree_opt; @@ -112,6 +113,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) int read_stdin = 0; init_revisions(opt, prefix); + gitmodules_config(); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ opt->abbrev = 0; opt->diff = 1; diff --git a/builtin/diff.c b/builtin/diff.c index 89ae89cde1..a43d326363 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -13,6 +13,7 @@ #include "revision.h" #include "log-tree.h" #include "builtin.h" +#include "submodule.h" struct blobinfo { unsigned char sha1[20]; @@ -279,6 +280,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) */ prefix = setup_git_directory_gently(&nongit); + gitmodules_config(); git_config(git_diff_ui_config, NULL); if (diff_use_color_default == -1) diff --git a/submodule.c b/submodule.c index d35a14dc06..1bcb0e90b1 100644 --- a/submodule.c +++ b/submodule.c @@ -65,6 +65,18 @@ static int submodule_config(const char *var, const char *value, void *cb) return 0; } +void gitmodules_config() +{ + const char *work_tree = get_git_work_tree(); + if (work_tree) { + struct strbuf gitmodules_path = STRBUF_INIT; + strbuf_addstr(&gitmodules_path, work_tree); + strbuf_addstr(&gitmodules_path, "/.gitmodules"); + git_config_from_file(submodule_config, gitmodules_path.buf, NULL); + strbuf_release(&gitmodules_path); + } +} + int parse_submodule_config_option(const char *var, const char *value) { int len; diff --git a/submodule.h b/submodule.h index 185a5ce6c6..8ac4037b56 100644 --- a/submodule.h +++ b/submodule.h @@ -5,6 +5,7 @@ struct diff_options; void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, const char *path); +void gitmodules_config(); int parse_submodule_config_option(const char *var, const char *value); void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *); void show_submodule_summary(FILE *f, const char *path, diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index 5022fa0b20..dccdd2348e 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -138,6 +138,32 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) git config --remove-section submodule.sub ' +test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' ' + git config --add -f .gitmodules submodule.sub.ignore none && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config -f .gitmodules submodule.sub.ignore all && + git diff HEAD >actual2 && + ! test -s actual2 && + git config -f .gitmodules submodule.sub.ignore untracked && + git diff HEAD >actual3 && + sed -e "1,/^@@/d" actual3 >actual3.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual3.body && + git config -f .gitmodules submodule.sub.ignore dirty && + git diff HEAD >actual4 && + ! test -s actual4 && + git config submodule.sub.ignore none && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config --remove-section submodule.sub && + rm .gitmodules +' + test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' ' ( cd sub && @@ -187,6 +213,25 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) git config --remove-section submodule.sub ' +test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' ' + git config --add -f .gitmodules submodule.sub.ignore all && + git diff HEAD >actual2 && + ! test -s actual2 && + git config -f .gitmodules submodule.sub.ignore untracked && + git diff HEAD >actual3 && + ! test -s actual3 && + git config -f .gitmodules submodule.sub.ignore dirty && + git diff HEAD >actual4 && + ! test -s actual4 && + git config submodule.sub.ignore none && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body && + git config --remove-section submodule.sub && + rm .gitmodules +' + test_expect_success 'git diff between submodule commits' ' git diff HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && @@ -219,6 +264,27 @@ test_expect_success 'git diff between submodule commits [.git/config]' ' git config --remove-section submodule.sub ' +test_expect_success 'git diff between submodule commits [.gitmodules]' ' + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git config --add -f .gitmodules submodule.sub.ignore dirty && + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body && + git config -f .gitmodules submodule.sub.ignore all && + git diff HEAD^..HEAD >actual && + ! test -s actual && + git config submodule.sub.ignore dirty && + git diff HEAD^..HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + git config --remove-section submodule.sub && + rm .gitmodules +' + test_expect_success 'git diff (empty submodule dir)' ' : >empty && rm -rf sub/* sub/.git && diff --git a/t/t7508-status.sh b/t/t7508-status.sh index e01b2a38cd..54f9e68654 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -872,10 +872,19 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un test_cmp expect output ' +test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' ' + git config --add -f .gitmodules submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore untracked && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -884,10 +893,19 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac test_cmp expect output ' +test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' ' + git config --add -f .gitmodules submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore dirty && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -897,10 +915,19 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with modifi test_cmp expect output ' +test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' ' + git config --add -f .gitmodules submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore dirty && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -941,10 +968,19 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodules w test_cmp expect output ' +test_expect_success ".gitmodules ignore=untracked doesn't suppress submodules with modified content" ' + git config --add -f .gitmodules submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success ".git/config ignore=untracked doesn't suppress submodules with modified content" ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore untracked && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -991,10 +1027,19 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodule su test_cmp expect output ' +test_expect_success ".gitmodules ignore=untracked doesn't suppress submodule summary" ' + git config --add -f .gitmodules submodule.sm.ignore untracked && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_success ".git/config ignore=untracked doesn't suppress submodule summary" ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore untracked && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' @@ -1002,15 +1047,22 @@ test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summar git status --ignore-submodules=dirty > output && test_cmp expect output ' +test_expect_success ".gitmodules ignore=dirty doesn't suppress submodule summary" ' + git config --add -f .gitmodules submodule.sm.ignore dirty && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary" ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore dirty && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' - cat > expect << EOF # On branch master # Changed but not updated: @@ -1037,10 +1089,19 @@ test_expect_success "--ignore-submodules=all suppresses submodule summary" ' test_cmp expect output ' +test_expect_failure '.gitmodules ignore=all suppresses submodule summary' ' + git config --add -f .gitmodules submodule.sm.ignore all && + git status > output && + test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm +' + test_expect_failure '.git/config ignore=all suppresses submodule summary' ' + git config --add -f .gitmodules submodule.sm.ignore none && git config --add submodule.sm.ignore all && git status > output && test_cmp expect output && + git config -f .gitmodules --remove-section submodule.sm && git config --remove-section submodule.sm ' From f9a8b529a51fcec83dc94a0aebc6a0c479d0a4ae Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1080/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 81c8b2e172..0ec6fe9b2f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -696,11 +696,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From c03a01e89214a0716f2cae0855d93df139c7eb35 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1081/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 3ef401498fd6c6affd03f9f4457c537ad43caa31 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1082/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 4b40b15b0881162aaa6fc6226324f29955b4259e Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1083/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From ce6e6a94349ea9275a70e6a30f701990e71afbb2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1084/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 37aea371f720c41830e1a2dcee3a7a23525a389a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 5 Aug 2010 10:49:55 +0200 Subject: [PATCH 1085/3720] Add the 'diff.ignoreSubmodules' config setting When you have a lot of submodules checked out, the time penalty to check for dirty submodules can easily imply a multiplication of the total time by the factor 20. This makes the difference between almost instantaneous (< 2 seconds) and unbearably slow (> 50 seconds) here, since the disk caches are constantly overloaded. To this end, the submodule.*.ignore config option was introduced, but it is per-submodule. This commit introduces a global config setting to set a default (porcelain) value for the --ignore-submodules option, keeping the default at 'none'. It can be overridden by the submodule.*.ignore setting and by the --ignore-submodules option. Incidentally, this commit fixes an issue with the overriding logic: multiple --ignore-submodules options would not clear the previously set flags. While at it, fix a typo in the documentation for submodule.*.ignore. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 7 ++++++- diff.c | 6 +++++- submodule.c | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 5594ce04ff..8384d124c0 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -832,6 +832,11 @@ diff.renames:: will enable basic rename detection. If set to "copies" or "copy", it will detect copies, as well. +diff.ignoreSubmodules:: + Sets the default value of --ignore-submodules. Note that this + affects only 'git diff' Porcelain, and not lower level 'diff' + commands such as 'git diff-files'. + diff.suppressBlankEmpty:: A boolean to inhibit the standard behavior of printing a space before each empty output line. Defaults to false. @@ -1769,7 +1774,7 @@ submodule..ignore:: submodules that have untracked files in their work tree as changed. This setting overrides any setting made in .gitmodules for this submodule, both settings can be overriden on the command line by using the - "--ignore-submodule" option. + "--ignore-submodules" option. tar.umask:: This variable can be used to restrict the permission bits of diff --git a/diff.c b/diff.c index bf6b9b129c..3b913af6d0 100644 --- a/diff.c +++ b/diff.c @@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static int diff_no_prefix; +static struct diff_options default_diff_options; static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, @@ -107,6 +108,9 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) if (!strcmp(var, "diff.wordregex")) return git_config_string(&diff_word_regex_cfg, var, value); + if (!strcmp(var, "diff.ignoresubmodules")) + handle_ignore_submodules_arg(&default_diff_options, value); + return git_diff_basic_config(var, value, cb); } @@ -2816,7 +2820,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) void diff_setup(struct diff_options *options) { - memset(options, 0, sizeof(*options)); + memcpy(options, &default_diff_options, sizeof(*options)); options->file = stdout; diff --git a/submodule.c b/submodule.c index 1bcb0e90b1..75f3368897 100644 --- a/submodule.c +++ b/submodule.c @@ -110,6 +110,10 @@ int parse_submodule_config_option(const char *var, const char *value) void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *arg) { + DIFF_OPT_CLR(diffopt, IGNORE_SUBMODULES); + DIFF_OPT_CLR(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES); + DIFF_OPT_CLR(diffopt, IGNORE_DIRTY_SUBMODULES); + if (!strcmp(arg, "all")) DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES); else if (!strcmp(arg, "untracked")) From 42cb3c4db38f8b5a86bc2e4851b9c18d8d7681d2 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 10 Aug 2010 00:22:27 +0200 Subject: [PATCH 1086/3720] Configure ignore option for submodule name instead of path Signed-off-by: Jens Lehmann Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 2 +- submodule.c | 45 ++++++++++------ t/t4027-diff-submodule.sh | 67 ++++++++++++++---------- t/t7508-status.sh | 105 +++++++++++++++++++++++--------------- 4 files changed, 133 insertions(+), 86 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 8384d124c0..470fd9323a 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1763,7 +1763,7 @@ submodule..update:: URL and other values found in the `.gitmodules` file. See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. -submodule..ignore:: +submodule..ignore:: Defines under what circumstances "git status" and the diff family show a submodule as modified. When set to "all", it will never be considered modified, "dirty" will ignore all changes to the submodules work tree and diff --git a/submodule.c b/submodule.c index 75f3368897..beb8622317 100644 --- a/submodule.c +++ b/submodule.c @@ -8,7 +8,8 @@ #include "diffcore.h" #include "string-list.h" -struct string_list config_ignore; +struct string_list config_name_for_path; +struct string_list config_ignore_for_name; static int add_submodule_odb(const char *path) { @@ -52,10 +53,13 @@ done: void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, const char *path) { - struct string_list_item *ignore_option; - ignore_option = unsorted_string_list_lookup(&config_ignore, path); - if (ignore_option) - handle_ignore_submodules_arg(diffopt, ignore_option->util); + struct string_list_item *path_option, *ignore_option; + path_option = unsorted_string_list_lookup(&config_name_for_path, path); + if (path_option) { + ignore_option = unsorted_string_list_lookup(&config_ignore_for_name, path_option->util); + if (ignore_option) + handle_ignore_submodules_arg(diffopt, ignore_option->util); + } } static int submodule_config(const char *var, const char *value, void *cb) @@ -80,28 +84,37 @@ void gitmodules_config() int parse_submodule_config_option(const char *var, const char *value) { int len; - struct string_list_item *ignore_option; - struct strbuf path = STRBUF_INIT; + struct string_list_item *config; + struct strbuf submodname = STRBUF_INIT; var += 10; /* Skip "submodule." */ len = strlen(var); - if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { + if ((len > 5) && !strcmp(var + len - 5, ".path")) { + strbuf_add(&submodname, var, len - 5); + config = unsorted_string_list_lookup(&config_name_for_path, value); + if (config) + free(config->util); + else + config = string_list_append(&config_name_for_path, xstrdup(value)); + config->util = strbuf_detach(&submodname, NULL); + strbuf_release(&submodname); + } else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { if (strcmp(value, "untracked") && strcmp(value, "dirty") && strcmp(value, "all") && strcmp(value, "none")) { warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var); return 0; } - strbuf_add(&path, var, len - 7); - ignore_option = unsorted_string_list_lookup(&config_ignore, path.buf); - if (ignore_option) - free(ignore_option->util); + strbuf_add(&submodname, var, len - 7); + config = unsorted_string_list_lookup(&config_ignore_for_name, submodname.buf); + if (config) + free(config->util); else - ignore_option = string_list_append(&config_ignore, - strbuf_detach(&path, NULL)); - strbuf_release(&path); - ignore_option->util = xstrdup(value); + config = string_list_append(&config_ignore_for_name, + strbuf_detach(&submodname, NULL)); + strbuf_release(&submodname); + config->util = xstrdup(value); return 0; } return 0; diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index dccdd2348e..1bc6e77a0d 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -115,52 +115,57 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)' ' test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.git/config]' ' - git config submodule.sub.ignore none && + git config submodule.subname.ignore none && + git config submodule.subname.path sub && git diff HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config submodule.sub.ignore all && + git config submodule.subname.ignore all && git diff HEAD >actual2 && ! test -s actual2 && - git config submodule.sub.ignore untracked && + git config submodule.subname.ignore untracked && git diff HEAD >actual3 && sed -e "1,/^@@/d" actual3 >actual3.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual3.body && - git config submodule.sub.ignore dirty && + git config submodule.subname.ignore dirty && git diff HEAD >actual4 && ! test -s actual4 && git diff HEAD --ignore-submodules=none >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config --remove-section submodule.sub + git config --remove-section submodule.subname ' test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' ' - git config --add -f .gitmodules submodule.sub.ignore none && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sub && git diff HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config -f .gitmodules submodule.sub.ignore all && + git config -f .gitmodules submodule.subname.ignore all && + git config -f .gitmodules submodule.subname.path sub && git diff HEAD >actual2 && ! test -s actual2 && - git config -f .gitmodules submodule.sub.ignore untracked && + git config -f .gitmodules submodule.subname.ignore untracked && git diff HEAD >actual3 && sed -e "1,/^@@/d" actual3 >actual3.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual3.body && - git config -f .gitmodules submodule.sub.ignore dirty && + git config -f .gitmodules submodule.subname.ignore dirty && git diff HEAD >actual4 && ! test -s actual4 && - git config submodule.sub.ignore none && + git config submodule.subname.ignore none && + git config submodule.subname.path sub && git diff HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config --remove-section submodule.sub && + git config --remove-section submodule.subname && + git config --remove-section -f .gitmodules submodule.subname && rm .gitmodules ' @@ -197,38 +202,42 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)' ' test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.git/config]' ' - git config submodule.sub.ignore all && + git config submodule.subname.ignore all && + git config submodule.subname.path sub && git diff HEAD >actual2 && ! test -s actual2 && - git config submodule.sub.ignore untracked && + git config submodule.subname.ignore untracked && git diff HEAD >actual3 && ! test -s actual3 && - git config submodule.sub.ignore dirty && + git config submodule.subname.ignore dirty && git diff HEAD >actual4 && ! test -s actual4 && git diff --ignore-submodules=none HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config --remove-section submodule.sub + git config --remove-section submodule.subname ' test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' ' - git config --add -f .gitmodules submodule.sub.ignore all && + git config --add -f .gitmodules submodule.subname.ignore all && + git config --add -f .gitmodules submodule.subname.path sub && git diff HEAD >actual2 && ! test -s actual2 && - git config -f .gitmodules submodule.sub.ignore untracked && + git config -f .gitmodules submodule.subname.ignore untracked && git diff HEAD >actual3 && ! test -s actual3 && - git config -f .gitmodules submodule.sub.ignore dirty && + git config -f .gitmodules submodule.subname.ignore dirty && git diff HEAD >actual4 && ! test -s actual4 && - git config submodule.sub.ignore none && + git config submodule.subname.ignore none && + git config submodule.subname.path sub && git diff HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subprev $subprev-dirty && test_cmp expect.body actual.body && - git config --remove-section submodule.sub && + git config --remove-section submodule.subname && + git config --remove-section -f .gitmodules submodule.subname && rm .gitmodules ' @@ -250,18 +259,19 @@ test_expect_success 'git diff between submodule commits [.git/config]' ' sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && test_cmp expect.body actual.body && - git config submodule.sub.ignore dirty && + git config submodule.subname.ignore dirty && + git config submodule.subname.path sub && git diff HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && test_cmp expect.body actual.body && - git config submodule.sub.ignore all && + git config submodule.subname.ignore all && git diff HEAD^..HEAD >actual && ! test -s actual && git diff --ignore-submodules=dirty HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && - git config --remove-section submodule.sub + git config --remove-section submodule.subname ' test_expect_success 'git diff between submodule commits [.gitmodules]' ' @@ -269,19 +279,22 @@ test_expect_success 'git diff between submodule commits [.gitmodules]' ' sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && test_cmp expect.body actual.body && - git config --add -f .gitmodules submodule.sub.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore dirty && + git config --add -f .gitmodules submodule.subname.path sub && git diff HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && test_cmp expect.body actual.body && - git config -f .gitmodules submodule.sub.ignore all && + git config -f .gitmodules submodule.subname.ignore all && git diff HEAD^..HEAD >actual && ! test -s actual && - git config submodule.sub.ignore dirty && + git config submodule.subname.ignore dirty && + git config submodule.subname.path sub && git diff HEAD^..HEAD >actual && sed -e "1,/^@@/d" actual >actual.body && expect_from_to >expect.body $subtip $subprev && - git config --remove-section submodule.sub && + git config --remove-section submodule.subname && + git config --remove-section -f .gitmodules submodule.subname && rm .gitmodules ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 54f9e68654..1b92845be8 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -873,19 +873,22 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un ' test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' ' - git config --add -f .gitmodules submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore untracked && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore untracked && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config --remove-section -f .gitmodules submodule.subname ' test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' ' @@ -894,19 +897,22 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac ' test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' ' - git config --add -f .gitmodules submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore dirty && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore dirty && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' ' @@ -916,19 +922,22 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with modifi ' test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' ' - git config --add -f .gitmodules submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore dirty && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore dirty && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' cat > expect << EOF @@ -969,19 +978,22 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodules w ' test_expect_success ".gitmodules ignore=untracked doesn't suppress submodules with modified content" ' - git config --add -f .gitmodules submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore untracked && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success ".git/config ignore=untracked doesn't suppress submodules with modified content" ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore untracked && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' head2=$(cd sm && git commit -q -m "2nd commit" foo && git rev-parse --short=7 --verify HEAD) @@ -1028,19 +1040,22 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodule su ' test_expect_success ".gitmodules ignore=untracked doesn't suppress submodule summary" ' - git config --add -f .gitmodules submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore untracked && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success ".git/config ignore=untracked doesn't suppress submodule summary" ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore untracked && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore untracked && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summary" ' @@ -1048,19 +1063,22 @@ test_expect_success "--ignore-submodules=dirty doesn't suppress submodule summar test_cmp expect output ' test_expect_success ".gitmodules ignore=dirty doesn't suppress submodule summary" ' - git config --add -f .gitmodules submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore dirty && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary" ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore dirty && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore dirty && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' cat > expect << EOF @@ -1090,19 +1108,22 @@ test_expect_success "--ignore-submodules=all suppresses submodule summary" ' ' test_expect_failure '.gitmodules ignore=all suppresses submodule summary' ' - git config --add -f .gitmodules submodule.sm.ignore all && + git config --add -f .gitmodules submodule.subname.ignore all && + git config --add -f .gitmodules submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm + git config -f .gitmodules --remove-section submodule.subname ' test_expect_failure '.git/config ignore=all suppresses submodule summary' ' - git config --add -f .gitmodules submodule.sm.ignore none && - git config --add submodule.sm.ignore all && + git config --add -f .gitmodules submodule.subname.ignore none && + git config --add -f .gitmodules submodule.subname.path sm && + git config --add submodule.subname.ignore all && + git config --add submodule.subname.path sm && git status > output && test_cmp expect output && - git config -f .gitmodules --remove-section submodule.sm && - git config --remove-section submodule.sm + git config --remove-section submodule.subname && + git config -f .gitmodules --remove-section submodule.subname ' test_done From 612735f3e10cfb1b2363820f4486c94e0d23f2fe Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Aug 2010 12:04:40 +0200 Subject: [PATCH 1087/3720] Fix typo in pack-objects' usage Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0e81673118..3756cf36ee 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -30,7 +30,7 @@ static const char pack_usage[] = " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n" " [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n" " [--reflog] [--stdout | base-name] [--include-tag]\n" - " [--keep-unreachable | --unpack-unreachable \n" + " [--keep-unreachable | --unpack-unreachable]\n" " [ Date: Wed, 11 Aug 2010 23:03:26 +0800 Subject: [PATCH 1088/3720] parse-options: enhance STOP_AT_NON_OPTION Make parse_options_step() report PARSE_OPT_NON_OPTION instead of PARSE_OPT_DONE to the caller, when it sees a non-option argument. This will help implementing a nonstandard option syntax that takes more than one parameters to an option, e.g. -L n1,m1 pathspec1 -L n2,m2 pathspec2 by directly calling parse_options_step(). The parse_options() API only calls parse_options_step() once, and its callers are not affected by this change. Thanks-to: Jonathan Nieder Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- parse-options.c | 3 ++- parse-options.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/parse-options.c b/parse-options.c index 0fa79bc31d..cbb49d3c8e 100644 --- a/parse-options.c +++ b/parse-options.c @@ -374,7 +374,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, if (parse_nodash_opt(ctx, arg, options) == 0) continue; if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) - break; + return PARSE_OPT_NON_OPTION; ctx->out[ctx->cpidx++] = ctx->argv[0]; continue; } @@ -456,6 +456,7 @@ int parse_options(int argc, const char **argv, const char *prefix, switch (parse_options_step(&ctx, options, usagestr)) { case PARSE_OPT_HELP: exit(129); + case PARSE_OPT_NON_OPTION: case PARSE_OPT_DONE: break; default: /* PARSE_OPT_UNKNOWN */ diff --git a/parse-options.h b/parse-options.h index 7435cdbf1d..407697a06b 100644 --- a/parse-options.h +++ b/parse-options.h @@ -161,7 +161,8 @@ extern NORETURN void usage_msg_opt(const char *msg, enum { PARSE_OPT_HELP = -1, PARSE_OPT_DONE, - PARSE_OPT_UNKNOWN + PARSE_OPT_NON_OPTION, + PARSE_OPT_UNKNOWN, }; /* From 3fd699ed44b2c27051e6a4d27c8cc69b77ce34f6 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:27 +0800 Subject: [PATCH 1089/3720] parse-options: add two helper functions 1. parse_options_current: get the current option/argument the API is dealing with; 2. parse_options_next: skip the current argument, moving to the next one. Unless 'keep' is set, discard the skipped argument from the final argument list. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- parse-options.c | 19 +++++++++++++++++++ parse-options.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/parse-options.c b/parse-options.c index cbb49d3c8e..e0c3641374 100644 --- a/parse-options.c +++ b/parse-options.c @@ -439,6 +439,25 @@ unknown: return PARSE_OPT_DONE; } +const char *parse_options_current(struct parse_opt_ctx_t *ctx) +{ + return ctx->argv[0]; +} + +int parse_options_next(struct parse_opt_ctx_t *ctx, int keep) +{ + if (ctx->argc <= 0) + return -1; + + if (keep) + ctx->out[ctx->cpidx++] = ctx->argv[0]; + + ctx->argc--; + ctx->argv++; + + return 0; +} + int parse_options_end(struct parse_opt_ctx_t *ctx) { memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); diff --git a/parse-options.h b/parse-options.h index 407697a06b..d3b1932f0e 100644 --- a/parse-options.h +++ b/parse-options.h @@ -187,6 +187,10 @@ extern int parse_options_step(struct parse_opt_ctx_t *ctx, const struct option *options, const char * const usagestr[]); +extern const char *parse_options_current(struct parse_opt_ctx_t *ctx); + +extern int parse_options_next(struct parse_opt_ctx_t *ctx, int keep); + extern int parse_options_end(struct parse_opt_ctx_t *ctx); extern int parse_options_concat(struct option *dst, size_t, struct option *src); From 71f23df8eae444c820b46c598ad4e6a726f95038 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:28 +0800 Subject: [PATCH 1090/3720] Add the basic data structure for line level history 'struct diff_line_range' is the main data structure to keep track of the line ranges we are currently interested in. The user starts digging from a line range, and after examining the diff that affects that range by a commit, we can find a new range that corresponds to this range. So, we will associate this new range with the commit's parent commit. There is one 'diff_line_range' for each file, and there are multiple 'struct line_range' in each 'diff_line_range'. In this way, we support multiple ranges. Within 'struct line_range', there are multiple 'struct print_range' which represent a diff hunk. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- Makefile | 2 + line.c | 454 +++++++++++++++++++++++++++++++++++++++++++++++++++++ line.h | 128 +++++++++++++++ revision.h | 8 +- 4 files changed, 590 insertions(+), 2 deletions(-) create mode 100644 line.c create mode 100644 line.h diff --git a/Makefile b/Makefile index bc3c57058f..5b44f0f44e 100644 --- a/Makefile +++ b/Makefile @@ -496,6 +496,7 @@ LIB_H += grep.h LIB_H += hash.h LIB_H += help.h LIB_H += levenshtein.h +LIB_H += line.h LIB_H += list-objects.h LIB_H += ll-merge.h LIB_H += log-tree.h @@ -582,6 +583,7 @@ LIB_OBJS += help.o LIB_OBJS += hex.o LIB_OBJS += ident.o LIB_OBJS += levenshtein.o +LIB_OBJS += line.o LIB_OBJS += list-objects.o LIB_OBJS += ll-merge.o LIB_OBJS += lockfile.o diff --git a/line.c b/line.c new file mode 100644 index 0000000000..775f222444 --- /dev/null +++ b/line.c @@ -0,0 +1,454 @@ +#include "cache.h" +#include "tag.h" +#include "blob.h" +#include "tree.h" +#include "diff.h" +#include "commit.h" +#include "decorate.h" +#include "revision.h" +#include "xdiff-interface.h" +#include "strbuf.h" +#include "log-tree.h" +#include "line.h" + +static void cleanup(struct diff_line_range *r) +{ + while (r) { + struct diff_line_range *next = r->next; + DIFF_LINE_RANGE_CLEAR(r); + free(r); + r = next; + } +} + +static struct object *verify_commit(struct rev_info *revs) +{ + struct object *commit = NULL; + int found = -1; + int i; + + for (i = 0; i < revs->pending.nr; i++) { + struct object *obj = revs->pending.objects[i].item; + if (obj->flags & UNINTERESTING) + continue; + while (obj->type == OBJ_TAG) + obj = deref_tag(obj, NULL, 0); + if (obj->type != OBJ_COMMIT) + die("Non commit %s?", revs->pending.objects[i].name); + if (commit) + die("More than one commit to dig from: %s and %s?", + revs->pending.objects[i].name, + revs->pending.objects[found].name); + commit = obj; + found = i; + } + + if (commit == NULL) + die("No commit specified?"); + + return commit; +} + +static void fill_blob_sha1(struct commit *commit, struct diff_line_range *r) +{ + unsigned mode; + unsigned char sha1[20]; + + while (r) { + if (get_tree_entry(commit->object.sha1, r->spec->path, + sha1, &mode)) + goto error; + fill_filespec(r->spec, sha1, mode); + r = r->next; + } + + return; +error: + die("There is no path %s in the commit", r->spec->path); +} + +static void fill_line_ends(struct diff_filespec *spec, long *lines, + unsigned long **line_ends) +{ + int num = 0, size = 50; + long cur = 0; + unsigned long *ends = NULL; + char *data = NULL; + + if (diff_populate_filespec(spec, 0)) + die("Cannot read blob %s", sha1_to_hex(spec->sha1)); + + ends = xmalloc(size * sizeof(*ends)); + ends[cur++] = 0; + data = spec->data; + while (num < spec->size) { + if (data[num] == '\n' || num == spec->size - 1) { + ALLOC_GROW(ends, (cur + 1), size); + ends[cur++] = num; + } + num++; + } + + /* shrink the array to fit the elements */ + ends = xrealloc(ends, cur * sizeof(*ends)); + *lines = cur; + *line_ends = ends; +} + +static const char *nth_line(struct diff_filespec *spec, long line, + long lines, unsigned long *line_ends) +{ + assert(line < lines); + assert(spec && spec->data); + + if (line == 0) + return (char *)spec->data; + else + return (char *)spec->data + line_ends[line] + 1; +} + +/* + * copied from blame.c, indeed, we can even to use this to test + * whether line log works. :) + */ +static const char *parse_loc(const char *spec, struct diff_filespec *file, + long lines, unsigned long *line_ends, + long begin, long *ret) +{ + char *term; + const char *line; + long num; + int reg_error; + regex_t regexp; + regmatch_t match[1]; + + /* Allow "-L ,+20" to mean starting at + * for 20 lines, or "-L ,-5" for 5 lines ending at + * . + */ + if (1 < begin && (spec[0] == '+' || spec[0] == '-')) { + num = strtol(spec + 1, &term, 10); + if (term != spec + 1) { + if (spec[0] == '-') + num = 0 - num; + if (0 < num) + *ret = begin + num - 2; + else if (!num) + *ret = begin; + else + *ret = begin + num; + return term; + } + return spec; + } + num = strtol(spec, &term, 10); + if (term != spec) { + *ret = num; + return term; + } + if (spec[0] != '/') + return spec; + + /* it could be a regexp of form /.../ */ + for (term = (char *) spec + 1; *term && *term != '/'; term++) { + if (*term == '\\') + term++; + } + if (*term != '/') + return spec; + + /* try [spec+1 .. term-1] as regexp */ + *term = 0; + begin--; /* input is in human terms */ + line = nth_line(file, begin, lines, line_ends); + + if (!(reg_error = regcomp(®exp, spec + 1, REG_NEWLINE)) && + !(reg_error = regexec(®exp, line, 1, match, 0))) { + const char *cp = line + match[0].rm_so; + const char *nline; + + while (begin++ < lines) { + nline = nth_line(file, begin, lines, line_ends); + if (line <= cp && cp < nline) + break; + line = nline; + } + *ret = begin; + regfree(®exp); + *term++ = '/'; + return term; + } else { + char errbuf[1024]; + regerror(reg_error, ®exp, errbuf, 1024); + die("-L parameter '%s': %s", spec + 1, errbuf); + } +} + +static void parse_range(long lines, unsigned long *line_ends, + struct line_range *r, struct diff_filespec *spec) +{ + const char *term; + + term = parse_loc(r->arg, spec, lines, line_ends, 1, &r->start); + if (*term == ',') { + term = parse_loc(term + 1, spec, lines, line_ends, + r->start + 1, &r->end); + if (*term) + die("-L parameter's argument should be ,"); + } + + if (*term) + die("-L parameter's argument should be ,"); + + if (r->start > r->end) { + long tmp = r->start; + r->start = r->end; + r->end = tmp; + } + + if (r->start < 1) + r->start = 1; + if (r->end >= lines) + r->end = lines - 1; +} + +static void parse_lines(struct commit *commit, struct diff_line_range *r) +{ + int i; + struct line_range *old_range = NULL; + long lines = 0; + unsigned long *ends = NULL; + + while (r) { + struct diff_filespec *spec = r->spec; + int num = r->nr; + assert(spec); + fill_blob_sha1(commit, r); + old_range = r->ranges; + r->ranges = NULL; + r->nr = r->alloc = 0; + fill_line_ends(spec, &lines, &ends); + for (i = 0; i < num; i++) { + parse_range(lines, ends, old_range + i, spec); + diff_line_range_insert(r, old_range[i].arg, + old_range[i].start, old_range[i].end); + } + + free(ends); + ends = NULL; + + r = r->next; + free(old_range); + } +} + +/* + * Insert a new line range into a diff_line_range struct, and keep the + * r->ranges sorted by their starting line number. + */ +struct line_range *diff_line_range_insert(struct diff_line_range *r, + const char *arg, int start, int end) +{ + int i = 0; + struct line_range *rs = r->ranges; + int left_merge = 0, right_merge = 0; + + assert(r != NULL); + assert(start <= end); + + if (r->nr == 0 || rs[r->nr - 1].end < start - 1) { + int num = 0; + DIFF_LINE_RANGE_GROW(r); + rs = r->ranges; + num = r->nr - 1; + rs[num].arg = arg; + rs[num].start = start; + rs[num].end = end; + return rs + num; + } + + for (; i < r->nr; i++) { + if (rs[i].end < start - 1) + continue; + if (rs[i].end == start - 1) { + rs[i].end = end; + right_merge = 1; + goto out; + } + + assert(rs[i].end > start - 1); + if (rs[i].start <= start) { + if (rs[i].end < end) { + rs[i].end = end; + right_merge = 1; + } + goto out; + } else if (rs[i].start <= end + 1) { + rs[i].start = start; + left_merge = 1; + if (rs[i].end < end) { + rs[i].end = end; + right_merge = 1; + } + goto out; + } else { + int num = r->nr - i; + DIFF_LINE_RANGE_GROW(r); + rs = r->ranges; + memmove(rs + i + 1, rs + i, num * sizeof(struct line_range)); + rs[i].arg = arg; + rs[i].start = start; + rs[i].end = end; + goto out; + } + } + +out: + assert(r->nr != i); + if (left_merge) { + int j = i; + for (; j > -1; j--) { + if (rs[j].end >= rs[i].start - 1) + if (rs[j].start < rs[i].start) + rs[i].start = rs[j].start; + } + memmove(rs + j + 1, rs + i, (r->nr - i) * sizeof(struct line_range)); + r->nr -= i - j - 1; + } + if (right_merge) { + int j = i; + for (; j < r->nr; j++) { + if (rs[j].start <= rs[i].end + 1) + if (rs[j].end > rs[i].end) + rs[i].end = rs[j].end; + } + if (j < r->nr) + memmove(rs + i + 1, rs + j, (r->nr - j) * sizeof(struct line_range)); + r->nr -= j - i - 1; + } + assert(r->nr); + + return rs + i; +} + +void diff_line_range_clear(struct diff_line_range *r) +{ + int i = 0, zero = 0; + + for (; i < r->nr; i++) { + struct line_range *rg = r->ranges + i; + RANGE_CLEAR(rg); + } + + if (r->prev) { + zero = 0; + if (r->prev->count == 1) + zero = 1; + free_filespec(r->prev); + if (zero) + r->prev = NULL; + } + if (r->spec) { + zero = 0; + if (r->spec->count == 1) + zero = 1; + free_filespec(r->spec); + if (zero) + r->spec = NULL; + } + + r->status = '\0'; + r->alloc = r->nr = 0; + + if (r->ranges) + free(r->ranges); + r->ranges = NULL; + r->next = NULL; +} + +void diff_line_range_append(struct diff_line_range *r, const char *arg) +{ + DIFF_LINE_RANGE_GROW(r); + r->ranges[r->nr - 1].arg = arg; +} + +struct diff_line_range *diff_line_range_merge(struct diff_line_range *out, + struct diff_line_range *other) +{ + struct diff_line_range *one = out, *two = other; + struct diff_line_range *pone = NULL; + + while (one) { + struct diff_line_range *ptwo; + two = other; + ptwo = other; + while (two) { + if (!strcmp(one->spec->path, two->spec->path)) { + int i = 0; + for (; i < two->nr; i++) { + diff_line_range_insert(one, NULL, + two->ranges[i].start, + two->ranges[i].end); + } + if (two == other) + other = other->next; + else + ptwo->next = two->next; + DIFF_LINE_RANGE_CLEAR(two); + free(two); + two = NULL; + + break; + } + + ptwo = two; + two = two->next; + } + + pone = one; + one = one->next; + } + pone->next = other; + + return out; +} + +void add_line_range(struct rev_info *revs, struct commit *commit, + struct diff_line_range *r) +{ + struct diff_line_range *ret = NULL; + + if (r != NULL) { + ret = lookup_decoration(&revs->line_range, &commit->object); + if (ret != NULL) + diff_line_range_merge(ret, r); + else + add_decoration(&revs->line_range, &commit->object, r); + commit->object.flags |= RANGE_UPDATE; + } +} + +struct diff_line_range *lookup_line_range(struct rev_info *revs, + struct commit *commit) +{ + struct diff_line_range *ret = NULL; + + ret = lookup_decoration(&revs->line_range, &commit->object); + return ret; +} + +void setup_line(struct rev_info *rev, struct diff_line_range *r) +{ + struct commit *commit = NULL; + struct diff_options *opt = &rev->diffopt; + + commit = (struct commit *)verify_commit(rev); + parse_lines(commit, r); + + add_line_range(rev, commit, r); + /* + * Note we support -M/-C to detect file rename + */ + opt->nr_paths = 0; + diff_tree_release_paths(opt); +} diff --git a/line.h b/line.h new file mode 100644 index 0000000000..a04af86327 --- /dev/null +++ b/line.h @@ -0,0 +1,128 @@ +#ifndef LINE_H +#define LINE_H + +#include "diffcore.h" + +struct rev_info; +struct commit; +struct diff_line_range; +struct diff_options; + +struct print_range { + int start, end; /* Line range of post-image */ + int pstart, pend; /* Line range of pre-image */ + int line_added : 1; /* whether this range is added */ +}; + +struct print_pair { + int alloc, nr; + struct print_range *ranges; +}; + +#define PRINT_RANGE_INIT(r) \ + do { \ + (r)->start = (r)->end = 0; \ + (r)->pstart = (r)->pend = 0; \ + (r)->line_added = 0; \ + } while (0) + +#define PRINT_PAIR_INIT(p) \ + do { \ + (p)->alloc = (p)->nr = 0; \ + (p)->ranges = NULL; \ + } while (0) + +#define PRINT_PAIR_GROW(p) \ + do { \ + (p)->nr++; \ + ALLOC_GROW((p)->ranges, (p)->nr, (p)->alloc); \ + } while (0) + +#define PRINT_PAIR_CLEAR(p) \ + do { \ + (p)->alloc = (p)->nr = 0; \ + if ((p)->ranges) \ + free((p)->ranges); \ + (p)->ranges = NULL; \ + } while (0) + +struct line_range { + const char *arg; /* The argument to specify this line range */ + long start, end; /* The interesting line range of current commit */ + long pstart, pend; /* The corresponding range of parent commit */ + struct print_pair pair; + /* The changed lines inside this range */ + unsigned int diff:1; +}; + +struct diff_line_range { + struct diff_filespec *prev; + struct diff_filespec *spec; + char status; + int alloc; + int nr; + struct line_range *ranges; + unsigned int touch:1, + diff:1; + struct diff_line_range *next; +}; + +#define RANGE_INIT(r) \ + do { \ + (r)->arg = NULL; \ + (r)->start = (r)->end = 0; \ + (r)->pstart = (r)->pend = 0; \ + PRINT_PAIR_INIT(&((r)->pair)); \ + (r)->diff = 0; \ + } while (0) + +#define RANGE_CLEAR(r) \ + do { \ + (r)->arg = NULL; \ + (r)->start = (r)->end = 0; \ + (r)->pstart = (r)->pend = 0; \ + PRINT_PAIR_CLEAR(&r->pair); \ + (r)->diff = 0; \ + } while (0) + +#define DIFF_LINE_RANGE_INIT(r) \ + do { \ + (r)->prev = (r)->spec = NULL; \ + (r)->status = '\0'; \ + (r)->alloc = (r)->nr = 0; \ + (r)->ranges = NULL; \ + (r)->next = NULL; \ + (r)->touch = 0; \ + (r)->diff = 0; \ + } while (0) + +#define DIFF_LINE_RANGE_GROW(r) \ + do { \ + (r)->nr++; \ + ALLOC_GROW((r)->ranges, (r)->nr, (r)->alloc); \ + RANGE_INIT(((r)->ranges + (r)->nr - 1)); \ + } while (0) + +#define DIFF_LINE_RANGE_CLEAR(r) \ + diff_line_range_clear((r)); + +extern struct line_range *diff_line_range_insert(struct diff_line_range *r, + const char *arg, int start, int end); + +extern void diff_line_range_append(struct diff_line_range *r, const char *arg); + +extern void diff_line_range_clear(struct diff_line_range *r); + +extern struct diff_line_range *diff_line_range_merge( + struct diff_line_range *out, + struct diff_line_range *other); + +extern void setup_line(struct rev_info *rev, struct diff_line_range *r); + +extern void add_line_range(struct rev_info *revs, struct commit *commit, + struct diff_line_range *r); + +extern struct diff_line_range *lookup_line_range(struct rev_info *revs, + struct commit *commit); + +#endif diff --git a/revision.h b/revision.h index 36fdf22b29..c0d50652cd 100644 --- a/revision.h +++ b/revision.h @@ -14,7 +14,8 @@ #define CHILD_SHOWN (1u<<6) #define ADDED (1u<<7) /* Parents already parsed and added? */ #define SYMMETRIC_LEFT (1u<<8) -#define ALL_REV_FLAGS ((1u<<9)-1) +#define RANGE_UPDATE (1u<<9) /* for line level traverse */ +#define ALL_REV_FLAGS ((1u<<10)-1) #define DECORATE_SHORT_REFS 1 #define DECORATE_FULL_REFS 2 @@ -68,7 +69,8 @@ struct rev_info { cherry_pick:1, bisect:1, ancestry_path:1, - first_parent_only:1; + first_parent_only:1, + line_level_traverse:1; /* Diff flags */ unsigned int diff:1, @@ -137,6 +139,8 @@ struct rev_info { /* commit counts */ int count_left; int count_right; + /* line level range that we are chasing */ + struct decoration line_range; }; #define REV_TREE_SAME 0 From f9daa44d212189ee504ee2459171943ea36fbf1c Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:29 +0800 Subject: [PATCH 1091/3720] Refactor parse_loc Both 'git blame -L' and 'git log -L' parse the same style of line number arguments, so put the 'parse_loc' function to line.c and export it. The caller of parse_loc should provide a callback function which is used to calculate the start position of the nth line. Other parts such as regexp search, line number parsing are abstracted and re-used. Note that, we can use '$' to specify the last line of a file. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- builtin/blame.c | 89 +++++-------------------------------------------- line.c | 52 ++++++++++++++++++----------- line.h | 5 +++ 3 files changed, 46 insertions(+), 100 deletions(-) diff --git a/builtin/blame.c b/builtin/blame.c index 01e62fdeb0..17b71cd3af 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -21,6 +21,7 @@ #include "parse-options.h" #include "utf8.h" #include "userdiff.h" +#include "line.h" static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file"; @@ -541,11 +542,16 @@ static void dup_entry(struct blame_entry *dst, struct blame_entry *src) dst->score = 0; } -static const char *nth_line(struct scoreboard *sb, int lno) +static const char *nth_line(struct scoreboard *sb, long lno) { return sb->final_buf + sb->lineno[lno]; } +static const char *nth_line_cb(void *data, long lno) +{ + return nth_line((struct scoreboard *)data, lno); +} + /* * It is known that lines between tlno to same came from parent, and e * has an overlap with that range. it also is known that parent's @@ -1906,83 +1912,6 @@ static const char *add_prefix(const char *prefix, const char *path) return prefix_path(prefix, prefix ? strlen(prefix) : 0, path); } -/* - * Parsing of (comma separated) one item in the -L option - */ -static const char *parse_loc(const char *spec, - struct scoreboard *sb, long lno, - long begin, long *ret) -{ - char *term; - const char *line; - long num; - int reg_error; - regex_t regexp; - regmatch_t match[1]; - - /* Allow "-L ,+20" to mean starting at - * for 20 lines, or "-L ,-5" for 5 lines ending at - * . - */ - if (1 < begin && (spec[0] == '+' || spec[0] == '-')) { - num = strtol(spec + 1, &term, 10); - if (term != spec + 1) { - if (spec[0] == '-') - num = 0 - num; - if (0 < num) - *ret = begin + num - 2; - else if (!num) - *ret = begin; - else - *ret = begin + num; - return term; - } - return spec; - } - num = strtol(spec, &term, 10); - if (term != spec) { - *ret = num; - return term; - } - if (spec[0] != '/') - return spec; - - /* it could be a regexp of form /.../ */ - for (term = (char *) spec + 1; *term && *term != '/'; term++) { - if (*term == '\\') - term++; - } - if (*term != '/') - return spec; - - /* try [spec+1 .. term-1] as regexp */ - *term = 0; - begin--; /* input is in human terms */ - line = nth_line(sb, begin); - - if (!(reg_error = regcomp(®exp, spec + 1, REG_NEWLINE)) && - !(reg_error = regexec(®exp, line, 1, match, 0))) { - const char *cp = line + match[0].rm_so; - const char *nline; - - while (begin++ < lno) { - nline = nth_line(sb, begin); - if (line <= cp && cp < nline) - break; - line = nline; - } - *ret = begin; - regfree(®exp); - *term++ = '/'; - return term; - } - else { - char errbuf[1024]; - regerror(reg_error, ®exp, errbuf, 1024); - die("-L parameter '%s': %s", spec + 1, errbuf); - } -} - /* * Parsing of -L option */ @@ -1993,9 +1922,9 @@ static void prepare_blame_range(struct scoreboard *sb, { const char *term; - term = parse_loc(bottomtop, sb, lno, 1, bottom); + term = parse_loc(bottomtop, nth_line_cb, sb, lno, 1, bottom); if (*term == ',') { - term = parse_loc(term + 1, sb, lno, *bottom + 1, top); + term = parse_loc(term + 1, nth_line_cb, sb, lno, *bottom + 1, top); if (*term) usage(blame_usage); } diff --git a/line.c b/line.c index 775f222444..e15ed5f61a 100644 --- a/line.c +++ b/line.c @@ -95,25 +95,29 @@ static void fill_line_ends(struct diff_filespec *spec, long *lines, *line_ends = ends; } -static const char *nth_line(struct diff_filespec *spec, long line, - long lines, unsigned long *line_ends) +struct nth_line_cb { + struct diff_filespec *spec; + long lines; + unsigned long *line_ends; +}; + +static const char *nth_line(void *data, long line) { - assert(line < lines); - assert(spec && spec->data); + struct nth_line_cb *d = data; + assert(d && line < d->lines); + assert(d->spec && d->spec->data); if (line == 0) - return (char *)spec->data; + return (char *)d->spec->data; else - return (char *)spec->data + line_ends[line] + 1; + return (char *)d->spec->data + d->line_ends[line] + 1; } /* - * copied from blame.c, indeed, we can even to use this to test - * whether line log works. :) + * Parsing of (comma separated) one item in the -L option */ -static const char *parse_loc(const char *spec, struct diff_filespec *file, - long lines, unsigned long *line_ends, - long begin, long *ret) +const char *parse_loc(const char *spec, nth_line_fn_t nth_line, + void *data, long lines, long begin, long *ret) { char *term; const char *line; @@ -122,6 +126,13 @@ static const char *parse_loc(const char *spec, struct diff_filespec *file, regex_t regexp; regmatch_t match[1]; + /* Catch the '$' matcher, now it is used to match the last + * line of the file. */ + if (spec[0] == '$') { + *ret = lines; + return spec + 1; + } + /* Allow "-L ,+20" to mean starting at * for 20 lines, or "-L ,-5" for 5 lines ending at * . @@ -160,7 +171,7 @@ static const char *parse_loc(const char *spec, struct diff_filespec *file, /* try [spec+1 .. term-1] as regexp */ *term = 0; begin--; /* input is in human terms */ - line = nth_line(file, begin, lines, line_ends); + line = nth_line(data, begin); if (!(reg_error = regcomp(®exp, spec + 1, REG_NEWLINE)) && !(reg_error = regexec(®exp, line, 1, match, 0))) { @@ -168,7 +179,7 @@ static const char *parse_loc(const char *spec, struct diff_filespec *file, const char *nline; while (begin++ < lines) { - nline = nth_line(file, begin, lines, line_ends); + nline = nth_line(data, begin); if (line <= cp && cp < nline) break; line = nline; @@ -188,10 +199,11 @@ static void parse_range(long lines, unsigned long *line_ends, struct line_range *r, struct diff_filespec *spec) { const char *term; + struct nth_line_cb data = {spec, lines, line_ends}; - term = parse_loc(r->arg, spec, lines, line_ends, 1, &r->start); + term = parse_loc(r->arg, nth_line, &data, lines - 1, 1, &r->start); if (*term == ',') { - term = parse_loc(term + 1, spec, lines, line_ends, + term = parse_loc(term + 1, nth_line, &data, lines - 1, r->start + 1, &r->end); if (*term) die("-L parameter's argument should be ,"); @@ -200,16 +212,16 @@ static void parse_range(long lines, unsigned long *line_ends, if (*term) die("-L parameter's argument should be ,"); + if (r->start < 1) + r->start = 1; + if (r->end >= lines) + r->end = lines - 1; + if (r->start > r->end) { long tmp = r->start; r->start = r->end; r->end = tmp; } - - if (r->start < 1) - r->start = 1; - if (r->end >= lines) - r->end = lines - 1; } static void parse_lines(struct commit *commit, struct diff_line_range *r) diff --git a/line.h b/line.h index a04af86327..5bde82810f 100644 --- a/line.h +++ b/line.h @@ -8,6 +8,8 @@ struct commit; struct diff_line_range; struct diff_options; +typedef const char *(*nth_line_fn_t)(void *data, long lno); + struct print_range { int start, end; /* Line range of post-image */ int pstart, pend; /* Line range of pre-image */ @@ -125,4 +127,7 @@ extern void add_line_range(struct rev_info *revs, struct commit *commit, extern struct diff_line_range *lookup_line_range(struct rev_info *revs, struct commit *commit); +const char *parse_loc(const char *spec, nth_line_fn_t nth_line, + void *data, long lines, long begin, long *ret); + #endif From b585e491cf779e7d1ad5f494eeeac9cd51043593 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:30 +0800 Subject: [PATCH 1092/3720] Parse the -L options With the two new APIs of parse options added in the previous commit, we parse the multiple '-L n,m ' syntax. Notice that users can give more than one '-L n,m' for each pathspec. And a pathspec with all its '-L' options maps to a single diff_line_range structure. This has the exactly the same semantics as 'git blame -L n,m ' because we refactored and reused the blame code. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- builtin/log.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/builtin/log.c b/builtin/log.c index 08b872263c..e7c5111e88 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -19,6 +19,7 @@ #include "remote.h" #include "string-list.h" #include "parse-options.h" +#include "line.h" /* Set a default date-time format for git log ("log.date" config variable) */ static const char *default_date_mode = NULL; @@ -27,11 +28,24 @@ static int default_show_root = 1; static int decoration_style; static const char *fmt_patch_subject_prefix = "PATCH"; static const char *fmt_pretty; +static const char *dashdash = "--"; -static const char * const builtin_log_usage = +static char builtin_log_usage[] = "git log [] [..] [[--] ...]\n" + "git log [] -L n,m \n" " or: git show [options] ..."; +static const char *log_opt_usage[] = { + builtin_log_usage, + NULL +}; + +struct line_opt_callback_data { + struct diff_line_range **range; + struct parse_opt_ctx_t *ctx; + struct rev_info *rev; +}; + static int parse_decoration_style(const char *var, const char *value) { switch (git_config_maybe_bool(var, value)) { @@ -49,12 +63,44 @@ static int parse_decoration_style(const char *var, const char *value) return -1; } +static int log_line_range_callback(const struct option *option, const char *arg, int unset) +{ + struct line_opt_callback_data *data = option->value; + struct diff_line_range *r = *data->range; + struct parse_opt_ctx_t *ctx = data->ctx; + + if (!arg) + return -1; + + if (r->nr == 0 && r->next == NULL) + ctx->out[ctx->cpidx++] = dashdash; + + diff_line_range_append(r, arg); + data->rev->line_level_traverse = 1; + return 0; +} + static void cmd_log_init(int argc, const char **argv, const char *prefix, struct rev_info *rev, struct setup_revision_opt *opt) { int i; int decoration_given = 0; struct userformat_want w; + const char *path = NULL, *fullpath = NULL; + static struct diff_line_range *range; + struct diff_line_range *r = NULL; + static struct parse_opt_ctx_t ctx; + static struct line_opt_callback_data line_cb = {&range, &ctx, NULL}; + static const struct option options[] = { + OPT_CALLBACK('L', NULL, &line_cb, "n,m", + "Process only line range n,m, counting from 1", + log_line_range_callback), + OPT_END() + }; + + line_cb.rev = rev; + range = xmalloc(sizeof(*range)); + DIFF_LINE_RANGE_INIT(range); rev->abbrev = DEFAULT_ABBREV; rev->commit_format = CMIT_FMT_DEFAULT; @@ -75,6 +121,56 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, */ if (argc == 2 && !strcmp(argv[1], "-h")) usage(builtin_log_usage); + + parse_options_start(&ctx, argc, argv, prefix, PARSE_OPT_KEEP_DASHDASH | + PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_STOP_AT_NON_OPTION); + for (;;) { + switch (parse_options_step(&ctx, options, log_opt_usage)) { + case PARSE_OPT_HELP: + exit(129); + case PARSE_OPT_DONE: + goto parse_done; + case PARSE_OPT_NON_OPTION: + path = parse_options_current(&ctx); + fullpath = prefix_path(prefix, prefix ? strlen(prefix) : 0, path); + range->spec = alloc_filespec(fullpath); + free((void *)fullpath); + if (range->nr == 0) { + if (range->next) { + die("Path %s need a -L option\n" + "If you want follow the history of the whole file " + "use 'git log -L 1,$ '", range->spec->path); + } else { + parse_options_next(&ctx, 1); + continue; + } + } + r = xmalloc(sizeof(*r)); + DIFF_LINE_RANGE_INIT(r); + r->next = range; + range = r; + parse_options_next(&ctx, 1); + continue; + case PARSE_OPT_UNKNOWN: + parse_options_next(&ctx, 1); + continue; + } + + parse_revision_opt(rev, &ctx, options, log_opt_usage); + } +parse_done: + argc = parse_options_end(&ctx); + + /* die if '-L ' with no pathspec follow */ + if (range->nr > 0 && range->spec == NULL) + die("Each -L should follow a path"); + /* clear up the last range */ + if (range->nr == 0) { + struct diff_line_range *r = range->next; + DIFF_LINE_RANGE_CLEAR(range); + range = r; + } + argc = setup_revisions(argc, argv, rev, opt); memset(&w, 0, sizeof(w)); @@ -125,6 +221,10 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, rev->show_decorations = 1; load_ref_decorations(decoration_style); } + + /* Test whether line level history is asked for */ + if (range && range->nr > 0) + setup_line(rev, range); } /* From 5d99e4e3c7c9c52ce819132973bd8b315a47282c Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:31 +0800 Subject: [PATCH 1093/3720] Export three functions from diff.c Use fill_metainfo to fill the line level diff meta data, emit_line to print out a line and quote_two to quote paths. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- diff.c | 6 +++--- diff.h | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/diff.c b/diff.c index 17873f3d9e..9efca958b2 100644 --- a/diff.c +++ b/diff.c @@ -144,7 +144,7 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return git_color_default_config(var, value, cb); } -static char *quote_two(const char *one, const char *two) +char *quote_two(const char *one, const char *two) { int need_one = quote_c_style(one, NULL, NULL, 1); int need_two = quote_c_style(two, NULL, NULL, 1); @@ -325,7 +325,7 @@ static void emit_line_0(struct diff_options *o, const char *set, const char *res fputc('\n', file); } -static void emit_line(struct diff_options *o, const char *set, const char *reset, +void emit_line(struct diff_options *o, const char *set, const char *reset, const char *line, int len) { emit_line_0(o, set, reset, line[0], line+1, len-1); @@ -2564,7 +2564,7 @@ static int similarity_index(struct diff_filepair *p) return p->score * 100 / MAX_SCORE; } -static void fill_metainfo(struct strbuf *msg, +void fill_metainfo(struct strbuf *msg, const char *name, const char *other, struct diff_filespec *one, diff --git a/diff.h b/diff.h index 063d10ac22..9676ab9243 100644 --- a/diff.h +++ b/diff.h @@ -12,6 +12,7 @@ struct diff_queue_struct; struct strbuf; struct diff_filespec; struct userdiff_driver; +struct diff_filepair; typedef void (*change_fn_t)(struct diff_options *options, unsigned old_mode, unsigned new_mode, @@ -301,4 +302,20 @@ extern size_t fill_textconv(struct userdiff_driver *driver, extern struct userdiff_driver *get_textconv(struct diff_filespec *one); +/* some output functions line.c need */ +extern void fill_metainfo(struct strbuf *msg, + const char *name, + const char *other, + struct diff_filespec *one, + struct diff_filespec *two, + struct diff_options *o, + struct diff_filepair *p, + int *must_show_header, + int use_color); + +extern void emit_line(struct diff_options *o, const char *set, const char *reset, + const char *line, int len); + +extern char *quote_two(const char *one, const char *two); + #endif /* DIFF_H */ From 636f3da57077d926525b6dc5030b786f13e04c4b Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:32 +0800 Subject: [PATCH 1094/3720] Add range clone functions Since diff_line_range can form a single list through its 'next' pointer, we provide two kind of clone. diff_line_range_clone: used to clone only the element node and set the element's 'next' pointer to NULL. diff_line_range_clone_deeply: used to clone the whole list of ranges. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- line.c | 39 +++++++++++++++++++++++++++++++++++++++ line.h | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/line.c b/line.c index e15ed5f61a..684e3bf56e 100644 --- a/line.c +++ b/line.c @@ -384,6 +384,45 @@ void diff_line_range_append(struct diff_line_range *r, const char *arg) r->ranges[r->nr - 1].arg = arg; } +struct diff_line_range *diff_line_range_clone(struct diff_line_range *r) +{ + struct diff_line_range *ret = xmalloc(sizeof(*ret)); + int i = 0; + + DIFF_LINE_RANGE_INIT(ret); + ret->ranges = xcalloc(r->nr, sizeof(struct line_range)); + memcpy(ret->ranges, r->ranges, sizeof(struct line_range) * r->nr); + + ret->alloc = ret->nr = r->nr; + + for (; i < ret->nr; i++) + PRINT_PAIR_INIT(&ret->ranges[i].pair); + + ret->spec = r->spec; + assert(ret->spec); + ret->spec->count++; + + return ret; +} + +struct diff_line_range *diff_line_range_clone_deeply(struct diff_line_range *r) +{ + struct diff_line_range *ret = NULL; + struct diff_line_range *tmp = NULL, *prev = NULL; + + assert(r); + ret = tmp = prev = diff_line_range_clone(r); + r = r->next; + while (r) { + tmp = diff_line_range_clone(r); + prev->next = tmp; + prev = tmp; + r = r->next; + } + + return ret; +} + struct diff_line_range *diff_line_range_merge(struct diff_line_range *out, struct diff_line_range *other) { diff --git a/line.h b/line.h index 5bde82810f..e03eff0dfb 100644 --- a/line.h +++ b/line.h @@ -119,6 +119,10 @@ extern struct diff_line_range *diff_line_range_merge( struct diff_line_range *out, struct diff_line_range *other); +extern struct diff_line_range *diff_line_range_clone(struct diff_line_range *r); + +extern struct diff_line_range *diff_line_range_clone_deeply(struct diff_line_range *r); + extern void setup_line(struct rev_info *rev, struct diff_line_range *r); extern void add_line_range(struct rev_info *revs, struct commit *commit, From 3583ee6caa8d767c42c27f6b65662bedfd92f21b Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Thu, 12 Aug 2010 21:09:58 +0800 Subject: [PATCH 1095/3720] map/take range to the parent of commits When going from a commit to its parents, we map the "interesting" range of lines according to the change made. For non-merge commit, we just run map_range on the ranges, which works as follows: 1. Run diffcore_std to find out the pre/postimage for each file. 2. Run xdi_diff_hunks on each interesting set of pre/postimages. 3. The map_range_cb callback is invoked for each hunk by the diff engine, and we use it to calculate the pre-image range from the post-image range in the function map_lines. For merge commits, we run map_range once for every parent. Simultaneously we use a take_range pass to eliminate all ranges that are identical. If any ranges remain after that, then the merge is considered non-trivial. The algorithm that maps lines from post-image to pre-image is in the function map_lines. Generally, we use simple line number calculation method to do the map. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- line.c | 502 +++++++++++++++++++++++++++++++++++++++++++++++++++++ revision.h | 5 +- 2 files changed, 506 insertions(+), 1 deletion(-) diff --git a/line.c b/line.c index 684e3bf56e..d5add7a398 100644 --- a/line.c +++ b/line.c @@ -503,3 +503,505 @@ void setup_line(struct rev_info *rev, struct diff_line_range *r) opt->nr_paths = 0; diff_tree_release_paths(opt); } + +struct take_range_cb_data { + struct diff_line_range *interesting; /* currently interesting ranges */ + struct diff_line_range *range; + /* the ranges corresponds to the interesting ranges of parent commit */ + long plno, tlno; + /* the last line number of diff hunk */ + int diff; + /* whether there is some line changes between the current + * commit and its parent */ +}; + +#define SCALE_FACTOR 4 +/* + * [p_start, p_end] represents the pre-image of current diff hunk, + * [t_start, t_end] represents the post-image of the current diff hunk, + * [start, end] represents the currently interesting line range in + * post-image, + * [o_start, o_end] represents the original line range that coresponds + * to current line range. + */ +void map_lines(long p_start, long p_end, long t_start, long t_end, + long start, long end, long *o_start, long *o_end) +{ + /* + * Normally, p_start should be less than p_end, so does the + * t_start and t_end. But when the line range is added from + * scratch, p_start will be greater than p_end. When the line + * range is deleted, t_start will be greater than t_end. + */ + if (p_start > p_end) { + *o_start = *o_end = 0; + return; + } + /* A deletion */ + if (t_start > t_end) { + *o_start = p_start; + *o_end = p_end; + return; + } + + if (start == t_start && end == t_end) { + *o_start = p_start; + *o_end = p_end; + return; + } + + /* + * A heuristic for lines mapping: + * + * When the pre-image is no more than 1/SCALE_FACTOR of the post-image, + * there is no effective way to find out which part of pre-image + * corresponds to the currently interesting range of post-image. + * And we are in the danger of tracking totally useless lines. + * So, we just treat all the post-image lines as added from scratch. + */ + if (SCALE_FACTOR * (p_end - p_start + 1) < (t_end - t_start + 1)) { + *o_start = *o_end = 0; + return; + } + + *o_start = p_start + start - t_start; + *o_end = p_end - (t_end - end); + + if (*o_start > *o_end) { + int temp = *o_start; + *o_start = *o_end; + *o_end = temp; + } + + if (*o_start < p_start) + *o_start = p_start; + if (*o_end > p_end) + *o_end = p_end; +} + +/* + * When same == 1: + * [p_start, p_end] represents the diff hunk line range of pre-image, + * [t_start, t_end] represents the diff hunk line range of post-image. + * When same == 0, they represent a range of identical lines between + * two images. + * + * This function find out the corresponding line ranges of currently + * interesting ranges which this diff hunk touches. + */ +static void map_range(struct take_range_cb_data *data, int same, + long p_start, long p_end, long t_start, long t_end) +{ + struct line_range *ranges = data->interesting->ranges; + long takens, takene, start, end; + int i = 0, out = 0, added = 0; + long op_start = p_start, op_end = p_end, ot_start = t_start, ot_end = t_end; + + for (; i < data->interesting->nr; i++) { + added = 0; + if (t_start > ranges[i].end) + continue; + if (t_end < ranges[i].start) + break; + + if (t_start > ranges[i].start) { + start = t_start; + takens = p_start; + if (t_end >= ranges[i].end) { + end = ranges[i].end; + takene = p_start + end - t_start; + } else { + end = t_end; + takene = p_end; + out = 1; + } + } else { + start = ranges[i].start; + takens = p_start + start - t_start; + if (t_end >= ranges[i].end) { + end = ranges[i].end; + takene = p_start + end - t_start; + } else { + end = t_end; + takene = p_end; + out = 1; + } + } + + if (!same) { + struct print_pair *pair = &ranges[i].pair; + struct print_range *rr = NULL; + PRINT_PAIR_GROW(pair); + rr = pair->ranges + pair->nr - 1; + PRINT_RANGE_INIT(rr); + rr->start = start; + rr->end = end; + map_lines(op_start, op_end, ot_start, ot_end, start, end, + &takens, &takene); + if (takens == 0 && takene == 0) { + added = 1; + rr->line_added = 1; + } + rr->pstart = takens; + rr->pend = takene; + data->diff = 1; + data->interesting->diff = 1; + ranges[i].diff = 1; + } + if (added) { + /* Code movement/copy detect here, now place two dummy statements here */ + int dummy = 0; + dummy = 1; + } else { + struct line_range *added_range = diff_line_range_insert(data->range, + NULL, takens, takene); + assert(added_range); + ranges[i].pstart = added_range->start; + ranges[i].pend = added_range->end; + } + + t_start = end + 1; + p_start = takene + 1; + + if (out) + break; + } +} + +/* + * [p_start, p_end] represents the line range of pre-image, + * [t_start, t_end] represents the line range of post-image, + * and they are identical lines. + * + * This function substracts out the identical lines between current + * commit and its parent, from currently interesting ranges. + */ +static void take_range(struct take_range_cb_data *data, + long p_start, long p_end, long t_start, long t_end) +{ + struct line_range *ranges = data->interesting->ranges; + long takens, takene, start, end; + int i = 0, out = 0, added = 0; + + for (; i < data->interesting->nr; i++) { + added = 0; + if (t_start > ranges[i].end) + continue; + if (t_end < ranges[i].start) + break; + + if (t_start > ranges[i].start) { + long tmp = ranges[i].end; + ranges[i].end = t_start - 1; + start = t_start; + takens = p_start; + if (t_end >= tmp) { + end = tmp; + takene = p_start + end - t_start; + p_start = takene + 1; + t_start = end + 1; + } else { + end = t_end; + takene = p_end; + diff_line_range_insert(data->interesting, NULL, + t_end + 1, tmp); + out = 1; + } + } else { + start = ranges[i].start; + takens = p_start + start - t_start; + if (t_end >= ranges[i].end) { + int num = data->interesting->nr - 1; + end = ranges[i].end; + takene = p_start + end - t_start; + t_start = end + 1; + p_start = takene + 1; + memmove(ranges + i, ranges + i + 1, (num - i) * sizeof(*ranges)); + data->interesting->nr = num; + i--; + } else { + end = t_end; + takene = p_end; + ranges[i].start = t_end + 1; + out = 1; + } + } + + diff_line_range_insert(data->range, NULL, takens, takene); + + if (out) + break; + } +} + +static void take_range_cb(void *data, long same, long p_next, long t_next) +{ + struct take_range_cb_data *d = data; + long p_start = d->plno + 1, t_start = d->tlno + 1; + long p_end = p_start + same - t_start, t_end = same; + + /* If one file is added from scratch, we should not bother to call + * take_range, since there is nothing to take + */ + if (t_end >= t_start) + take_range(d, p_start, p_end, t_start, t_end); + d->plno = p_next; + d->tlno = t_next; +} + +static void map_range_cb(void *data, long same, long p_next, long t_next) +{ + struct take_range_cb_data *d = data; + + long p_start = d->plno + 1; + long t_start = d->tlno + 1; + long p_end = same - t_start + p_start; + long t_end = same; + + /* Firstly, take the unchanged lines from child */ + if (t_end >= t_start) + map_range(d, 1, p_start, p_end, t_start, t_end); + + /* find out which lines to print */ + t_start = same + 1; + p_start = d->plno + t_start - d->tlno; + map_range(d, 0, p_start, p_next, t_start, t_next); + + d->plno = p_next; + d->tlno = t_next; +} + +/* + * We support two kinds of operation in this function: + * 1. map == 0, take the same lines from the current commit and assign it + * to parent; + * 2. map == 1, in addition to the same lines, we also map the changed lines + * from the current commit to the parent according to the + * diff output. + * take_range_cb and take_range are used to take same lines from current commit + * to parents. + * map_range_cb and map_range are used to map line ranges to the parent. + */ +static void assign_range_to_parent(struct rev_info *rev, struct commit *c, + struct commit *p, struct diff_line_range *r, + struct diff_options *opt, int map) +{ + struct diff_line_range *rr = xmalloc(sizeof(*rr)); + struct diff_line_range *cr = rr, *prev_r = rr; + struct diff_line_range *rg = NULL; + struct tree_desc desc1, desc2; + void *tree1 = NULL, *tree2 = NULL; + unsigned long size1, size2; + struct diff_queue_struct *queue; + struct take_range_cb_data cb = {NULL, cr, 0, 0}; + xpparam_t xpp; + xdemitconf_t xecfg; + int i, diff = 0; + xdiff_emit_hunk_consume_fn fn = map ? map_range_cb : take_range_cb; + + DIFF_LINE_RANGE_INIT(cr); + memset(&xpp, 0, sizeof(xpp)); + memset(&xecfg, 0, sizeof(xecfg)); + xecfg.ctxlen = xecfg.interhunkctxlen = 0; + + /* + * Compose up two trees, for root commit, we make up a empty tree. + */ + assert(c); + tree2 = read_object_with_reference(c->tree->object.sha1, "tree", + &size2, NULL); + if (tree2 == NULL) + die("Unable to read tree (%s)", sha1_to_hex(c->tree->object.sha1)); + init_tree_desc(&desc2, tree2, size2); + if (p) { + tree1 = read_object_with_reference(p->tree->object.sha1, + "tree", &size1, NULL); + if (tree1 == NULL) + die("Unable to read tree (%s)", + sha1_to_hex(p->tree->object.sha1)); + init_tree_desc(&desc1, tree1, size1); + } else { + init_tree_desc(&desc1, "", 0); + } + + DIFF_QUEUE_CLEAR(&diff_queued_diff); + diff_tree(&desc1, &desc2, "", opt); + diffcore_std(opt); + + queue = &diff_queued_diff; + for (i = 0; i < queue->nr; i++) { + struct diff_filepair *pair = queue->queue[i]; + struct diff_line_range *rg = r; + mmfile_t file_p, file_t; + assert(pair->two->path); + while (rg) { + assert(rg->spec->path); + if (!strcmp(rg->spec->path, pair->two->path)) + break; + rg = rg->next; + } + + if (rg == NULL) + continue; + rg->touch = 1; + if (rg->nr == 0) + continue; + + rg->status = pair->status; + assert(pair->two->sha1_valid); + diff_populate_filespec(pair->two, 0); + file_t.ptr = pair->two->data; + file_t.size = pair->two->size; + + if (rg->prev) + free_filespec(rg->prev); + rg->prev = pair->one; + rg->prev->count++; + if (pair->one->sha1_valid) { + diff_populate_filespec(pair->one, 0); + file_p.ptr = pair->one->data; + file_p.size = pair->one->size; + } else { + file_p.ptr = ""; + file_p.size = 0; + } + + if (cr->nr != 0) { + struct diff_line_range *tmp = xmalloc(sizeof(*tmp)); + cr->next = tmp; + prev_r = cr; + cr = tmp; + } else if (cr->spec) + DIFF_LINE_RANGE_CLEAR(cr); + + DIFF_LINE_RANGE_INIT(cr); + if (pair->one->sha1_valid) { + cr->spec = pair->one; + cr->spec->count++; + } + + cb.interesting = rg; + cb.range = cr; + cb.diff = 0; + cb.plno = cb.tlno = 0; + xdi_diff_hunks(&file_p, &file_t, fn, &cb, &xpp, &xecfg); + if (cb.diff) + diff = 1; + /* + * The remain part is the same part. + * Instead of calculating the true line number of the two files, + * use the biggest integer. + */ + if (map) + map_range(&cb, 1, cb.plno + 1, INT_MAX, cb.tlno + 1, INT_MAX); + else + take_range(&cb, cb.plno + 1, INT_MAX, cb.tlno + 1, INT_MAX); + } + opt->output_format = DIFF_FORMAT_NO_OUTPUT; + diff_flush(opt); + + /* + * Collect the untouch ranges, this comes from the files not changed + * between two commit. + */ + rg = r; + while (rg) { + /* clear the touch one to make it usable in next round */ + if (rg->touch) { + rg->touch = 0; + } else { + struct diff_line_range *untouch = diff_line_range_clone(rg); + if (prev_r == rr && rr->nr == 0) { + rr = prev_r = untouch; + } else { + prev_r->next = untouch; + prev_r = untouch; + } + } + rg = rg->next; + } + + if (cr->nr == 0) { + DIFF_LINE_RANGE_CLEAR(cr); + free(cr); + if (prev_r == cr) + rr = NULL; + else + prev_r->next = NULL; + } + + if (rr) { + assert(p); + add_line_range(rev, p, rr); + } + + /* and the ranges of current commit c is updated */ + c->object.flags &= ~RANGE_UPDATE; + if (diff) + c->object.flags |= NEED_PRINT; + + if (tree1) + free(tree1); + if (tree2) + free(tree2); +} + +static void diff_update_parent_range(struct rev_info *rev, + struct commit *commit) +{ + struct diff_line_range *r = lookup_line_range(rev, commit); + struct commit_list *parents = commit->parents; + struct commit *c = NULL; + if (parents) { + assert(parents->next == NULL); + c = parents->item; + } + + assign_range_to_parent(rev, commit, c, r, &rev->diffopt, 1); +} + +static void assign_parents_range(struct rev_info *rev, struct commit *commit) +{ + struct commit_list *parents = commit->parents; + struct diff_line_range *r = lookup_line_range(rev, commit); + struct diff_line_range *evil = NULL, *range = NULL; + int nontrivial = 0; + + /* + * If we are in linear history, update range and flush the patch if + * necessary + */ + if (parents == NULL || parents->next == NULL) + return diff_update_parent_range(rev, commit); + + /* + * Loop on the parents and assign the ranges to different + * parents, if there is any range left, this commit must + * be an evil merge. + */ + evil = diff_line_range_clone_deeply(r); + parents = commit->parents; + while (parents) { + struct commit *p = parents->item; + assign_range_to_parent(rev, commit, p, r, &rev->diffopt, 1); + assign_range_to_parent(rev, commit, p, evil, &rev->diffopt, 0); + parents = parents->next; + } + + /* + * yes, this must be an evil merge. + */ + range = evil; + while (range) { + if (range->nr) { + commit->object.flags |= NEED_PRINT | EVIL_MERGE; + nontrivial = 1; + } + range = range->next; + } + + if (nontrivial) + add_decoration(&rev->nontrivial_merge, &commit->object, evil); + else + cleanup(evil); +} diff --git a/revision.h b/revision.h index c0d50652cd..2627ec4d6b 100644 --- a/revision.h +++ b/revision.h @@ -15,7 +15,9 @@ #define ADDED (1u<<7) /* Parents already parsed and added? */ #define SYMMETRIC_LEFT (1u<<8) #define RANGE_UPDATE (1u<<9) /* for line level traverse */ -#define ALL_REV_FLAGS ((1u<<10)-1) +#define NEED_PRINT (1u<<10) +#define EVIL_MERGE (1u<<11) +#define ALL_REV_FLAGS ((1u<<12)-1) #define DECORATE_SHORT_REFS 1 #define DECORATE_FULL_REFS 2 @@ -141,6 +143,7 @@ struct rev_info { int count_right; /* line level range that we are chasing */ struct decoration line_range; + struct decoration nontrivial_merge; }; #define REV_TREE_SAME 0 From fdf5ea61f300d919040fae84b5df8848d572154b Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:34 +0800 Subject: [PATCH 1096/3720] Print the line log 'struct line_chunk' is used to make sure each file is scanned only once when printing the lines. We track the starting line number and the offsets of all lines in the range in this struct. We use two functions from diff.c to generate meta info and hunk headers in the usual format. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- line.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/line.c b/line.c index d5add7a398..92ae15fbda 100644 --- a/line.c +++ b/line.c @@ -1005,3 +1005,241 @@ static void assign_parents_range(struct rev_info *rev, struct commit *commit) else cleanup(evil); } + +struct line_chunk { + int lone, ltwo; + const char *one, *two; + const char *one_end, *two_end; + struct diff_line_range *range; +}; + +static void flush_lines(struct diff_options *opt, const char **ptr, const char *end, + int slno, int elno, int *lno, const char *color, const char heading) +{ + const char *p = *ptr; + struct strbuf buf = STRBUF_INIT; + const char *reset; + + if (*color) + reset = diff_get_color_opt(opt, DIFF_RESET); + else + reset = ""; + + strbuf_addf(&buf, "%s%c", color, heading); + while (*ptr < end && *lno < slno) { + if (**ptr == '\n') { + (*lno)++; + if (*lno == slno) { + (*ptr)++; + break; + } + } + (*ptr)++; + } + assert(*ptr <= end); + p = *ptr; + + while (*ptr < end && *lno <= elno) { + if (**ptr == '\n') { + fprintf(opt->file, "%s", buf.buf); + if (*ptr - p) + fwrite(p, *ptr - p, 1, opt->file); + fprintf(opt->file, "%s\n", reset); + p = *ptr + 1; + (*lno)++; + } + (*ptr)++; + } + if (*lno <= elno) { + fprintf(opt->file, "%s", buf.buf); + if (*ptr - p) + fwrite(p, *ptr - p, 1, opt->file); + fprintf(opt->file, "%s\n", reset); + } + strbuf_release(&buf); +} + +static void diff_flush_range(struct diff_options *opt, struct line_chunk *chunk, + struct line_range *range) +{ + struct print_pair *pair = &range->pair; + const char *old = diff_get_color_opt(opt, DIFF_FILE_OLD); + const char *new = diff_get_color_opt(opt, DIFF_FILE_NEW); + int i, cur = range->start; + + for (i = 0; i < pair->nr; i++) { + struct print_range *pr = pair->ranges + i; + if (cur < pr->start) + flush_lines(opt, &chunk->two, chunk->two_end, + cur, pr->start - 1, &chunk->ltwo, "", ' '); + + if (!pr->line_added) + flush_lines(opt, &chunk->one, chunk->one_end, + pr->pstart, pr->pend, &chunk->lone, old, '-'); + flush_lines(opt, &chunk->two, chunk->two_end, + pr->start, pr->end, &chunk->ltwo, new, '+'); + + cur = pr->end + 1; + } + + if (cur <= range->end) { + flush_lines(opt, &chunk->two, chunk->two_end, + cur, range->end, &chunk->ltwo, "", ' '); + } +} + +static void diff_flush_chunks(struct diff_options *opt, struct line_chunk *chunk) +{ + struct diff_line_range *range = chunk->range; + const char *set = diff_get_color_opt(opt, DIFF_FRAGINFO); + const char *reset = diff_get_color_opt(opt, DIFF_RESET); + int i; + + for (i = 0; i < range->nr; i++) { + struct line_range *r = range->ranges + i; + long lenp = r->pend - r->pstart + 1, pstart = r->pstart; + long len = r->end - r->start + 1; + if (pstart == 0) + lenp = 0; + + fprintf(opt->file, "%s@@ -%ld,%ld +%ld,%ld @@%s\n", + set, pstart, lenp, r->start, len, reset); + + diff_flush_range(opt, chunk, r); + } +} + +static void diff_flush_filepair(struct rev_info *rev, struct diff_line_range *range) +{ + struct diff_options *opt = &rev->diffopt; + struct diff_filespec *one = range->prev, *two = range->spec; + struct diff_filepair p = {one, two, range->status, 0}; + struct strbuf header = STRBUF_INIT, meta = STRBUF_INIT; + const char *a_prefix, *b_prefix; + const char *name_a, *name_b, *a_one, *b_two; + const char *lbl[2]; + const char *set = diff_get_color_opt(opt, DIFF_METAINFO); + const char *reset = diff_get_color_opt(opt, DIFF_RESET); + struct line_chunk chunk; + int must_show_header; + + /* + * the ranges that touch no different file, in this case + * the line number will not change, and of course we have + * no sensible rang->pair since there is no diff run. + */ + if (one == NULL) + return; + + if (range->status == DIFF_STATUS_DELETED) + die("We are following an nonexistent file, interesting!"); + + name_a = one->path; + name_b = two->path; + fill_metainfo(&meta, name_a, name_b, one, two, opt, &p, &must_show_header, + DIFF_OPT_TST(opt, COLOR_DIFF)); + + diff_set_mnemonic_prefix(opt, "a/", "b/"); + if (DIFF_OPT_TST(opt, REVERSE_DIFF)) { + a_prefix = opt->b_prefix; + b_prefix = opt->a_prefix; + } else { + a_prefix = opt->a_prefix; + b_prefix = opt->b_prefix; + } + + name_a = DIFF_FILE_VALID(one) ? name_a : name_b; + name_b = DIFF_FILE_VALID(two) ? name_b : name_a; + + a_one = quote_two(a_prefix, name_a + (*name_a == '/')); + b_two = quote_two(b_prefix, name_b + (*name_b == '/')); + lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; + lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; + strbuf_addf(&header, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset); + if (lbl[0][0] == '/') { + strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset); + } else if (lbl[1][0] == '/') { + strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset); + } else if (one->mode != two->mode) { + strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset); + strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset); + } + + fprintf(opt->file, "%s%s", header.buf, meta.buf); + strbuf_release(&meta); + strbuf_release(&header); + fprintf(opt->file, "%s--- %s%s\n", set, lbl[0], reset); + fprintf(opt->file, "%s+++ %s%s\n", set, lbl[1], reset); + free((void *)a_one); + free((void *)b_two); + + chunk.one = one->data; + chunk.one_end = (const char *)one->data + one->size; + chunk.lone = 1; + chunk.two = two->data; + chunk.two_end = (const char *)two->data + two->size; + chunk.ltwo = 1; + chunk.range = range; + diff_flush_chunks(&rev->diffopt, &chunk); +} + +#define EVIL_MERGE_STR "nontrivial merge found" +static void flush_nontrivial_merge(struct rev_info *rev, struct diff_line_range *range) +{ + struct diff_options *opt = &rev->diffopt; + const char *reset = diff_get_color_opt(opt, DIFF_RESET); + const char *frag = diff_get_color_opt(opt, DIFF_FRAGINFO); + const char *meta = diff_get_color_opt(opt, DIFF_METAINFO); + const char *new = diff_get_color_opt(opt, DIFF_FILE_NEW); + + fprintf(opt->file, "%s%s%s\n", meta, EVIL_MERGE_STR, reset); + + while (range) { + if (range->nr) { + int lno = 1; + const char *ptr = range->spec->data; + const char *end = (const char *)range->spec->data + range->spec->size; + int i = 0; + fprintf(opt->file, "%s%s%s\n\n", meta, range->spec->path, reset); + for (; i < range->nr; i++) { + struct line_range *r = range->ranges + i; + fprintf(opt->file, "%s@@ %ld,%ld @@%s\n", frag, r->start, + r->end - r->start + 1, reset); + flush_lines(opt, &ptr, end, r->start, r->end, + &lno, new, ' '); + } + fprintf(opt->file, "\n"); + } + range = range->next; + } +} + +static void line_log_flush(struct rev_info *rev, struct commit *c) +{ + struct diff_line_range *range = lookup_line_range(rev, c); + struct diff_line_range *nontrivial = lookup_decoration(&rev->nontrivial_merge, &c->object); + struct log_info log; + + if (range == NULL) + return; + + log.commit = c; + log.parent = NULL; + rev->loginfo = &log; + show_log(rev); + rev->loginfo = NULL; + /* + * Add a new line after each commit message, of course we should + * add --graph alignment later when the patches comes to master. + */ + fprintf(rev->diffopt.file, "\n"); + + if (c->object.flags & EVIL_MERGE) + return flush_nontrivial_merge(rev, nontrivial); + + while (range) { + if (range->diff) + diff_flush_filepair(rev, range); + range = range->next; + } +} From db26ae04da2f836ef7bd291e46808393bcc2c2fd Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:35 +0800 Subject: [PATCH 1097/3720] Hook line history into cmd_log, ensuring a topo-ordered walk To correctly track the line ranges over several branches, we must make sure that we have processed all children before reaching the commit itself. Thus we introduce a first pass in cmd_line_log that runs prepare_revision_walk to achieve the topological ordering. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- builtin/log.c | 5 ++++- line.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ line.h | 2 ++ revision.c | 6 ++++++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/builtin/log.c b/builtin/log.c index e7c5111e88..637bceafc4 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -615,7 +615,10 @@ int cmd_log(int argc, const char **argv, const char *prefix) memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; cmd_log_init(argc, argv, prefix, &rev, &opt); - return cmd_log_walk(&rev); + if (rev.line_level_traverse) + return cmd_line_log_walk(&rev); + else + return cmd_log_walk(&rev); } /* format-patch */ diff --git a/line.c b/line.c index 92ae15fbda..f059941bfd 100644 --- a/line.c +++ b/line.c @@ -1243,3 +1243,55 @@ static void line_log_flush(struct rev_info *rev, struct commit *c) range = range->next; } } + +int cmd_line_log_walk(struct rev_info *rev) +{ + struct commit *commit; + struct commit_list *list = NULL; + struct diff_line_range *r = NULL; + + if (prepare_revision_walk(rev)) + die("revision walk prepare failed"); + + list = rev->commits; + if (list) { + list->item->object.flags |= RANGE_UPDATE; + list = list->next; + } + /* Clear the flags */ + while (list) { + list->item->object.flags &= ~(RANGE_UPDATE | EVIL_MERGE | NEED_PRINT); + list = list->next; + } + + list = rev->commits; + while (list) { + struct commit_list *need_free = list; + commit = list->item; + + if (commit->object.flags & RANGE_UPDATE) + assign_parents_range(rev, commit); + + if (commit->object.flags & NEED_PRINT) + line_log_flush(rev, commit); + + r = lookup_line_range(rev, commit); + if (r) { + cleanup(r); + r = NULL; + add_line_range(rev, commit, r); + } + + r = lookup_decoration(&rev->nontrivial_merge, &commit->object); + if (r) { + cleanup(r); + r = NULL; + add_decoration(&rev->nontrivial_merge, &commit->object, r); + } + + list = list->next; + free(need_free); + } + + return 0; +} diff --git a/line.h b/line.h index e03eff0dfb..202130fa12 100644 --- a/line.h +++ b/line.h @@ -134,4 +134,6 @@ extern struct diff_line_range *lookup_line_range(struct rev_info *revs, const char *parse_loc(const char *spec, nth_line_fn_t nth_line, void *data, long lines, long begin, long *ret); +extern int cmd_line_log_walk(struct rev_info *rev); + #endif diff --git a/revision.c b/revision.c index 7e82efd932..25c9a942f8 100644 --- a/revision.c +++ b/revision.c @@ -1637,6 +1637,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->combine_merges) revs->ignore_merges = 0; revs->diffopt.abbrev = revs->abbrev; + + if (revs->line_level_traverse) { + revs->limited = 1; + revs->topo_order = 1; + } + if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); From 89e8dbeb5c88fd344ac9e91e9f851d032aeb85c2 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:36 +0800 Subject: [PATCH 1098/3720] Make rewrite_parents public to other part of git The function rewrite_one is used to rewrite a single parent of the current commit, and is used by rewrite_parents to rewrite all the parents. Decouple the dependence between them by making rewrite_one a callback function that is passed to rewrite_parents. Then export rewrite_parents for reuse by the line history browser. We will use this function in line.c. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- revision.c | 13 ++++--------- revision.h | 10 ++++++++++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/revision.c b/revision.c index 25c9a942f8..fb089784e9 100644 --- a/revision.c +++ b/revision.c @@ -1893,12 +1893,6 @@ int prepare_revision_walk(struct rev_info *revs) return 0; } -enum rewrite_result { - rewrite_one_ok, - rewrite_one_noparents, - rewrite_one_error -}; - static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp) { struct commit_list *cache = NULL; @@ -1920,12 +1914,13 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp } } -static int rewrite_parents(struct rev_info *revs, struct commit *commit) +int rewrite_parents(struct rev_info *revs, struct commit *commit, + rewrite_parent_fn_t rewrite_parent) { struct commit_list **pp = &commit->parents; while (*pp) { struct commit_list *parent = *pp; - switch (rewrite_one(revs, &parent->item)) { + switch (rewrite_parent(revs, &parent->item)) { case rewrite_one_ok: break; case rewrite_one_noparents: @@ -1993,7 +1988,7 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) if (action == commit_show && !revs->show_all && revs->prune && revs->dense && want_ancestry(revs)) { - if (rewrite_parents(revs, commit) < 0) + if (rewrite_parents(revs, commit, rewrite_one) < 0) return commit_error; } return action; diff --git a/revision.h b/revision.h index 2627ec4d6b..48222f678f 100644 --- a/revision.h +++ b/revision.h @@ -199,4 +199,14 @@ enum commit_action { extern enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit); extern enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit); +enum rewrite_result { + rewrite_one_ok, + rewrite_one_noparents, + rewrite_one_error +}; + +typedef enum rewrite_result (*rewrite_parent_fn_t)(struct rev_info *revs, struct commit **pp); + +extern int rewrite_parents(struct rev_info *revs, struct commit *commit, + rewrite_parent_fn_t rewrite_parent); #endif From 107880a701e9cd42f2a537b7ba74d3cf596a3ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 12 Aug 2010 22:08:15 +0000 Subject: [PATCH 1099/3720] gettext: setlocale(LC_CTYPE, "") breaks Git's C function assumptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the setlocale/LC_CTYPE call from gettext.c, we only need setlocale/LC_MESSAGES to use the message catalog, and setting LC_CTYPE from the environment breaks Git's assumptions about C library functions. Under a non-C locale functions like vsnprintf become locale sensitive, so that they'll e.g. refuse to process ISO-8895-1 data under a UTF-8 locale. This triggered a "your vsnprintf is broken" error on Git's own repository when inspecting v0.99.6~1 under a UTF-8 locale. That commit contains a ISO-8859-1 encoded author name, which the locale aware vsnprintf(3) won't interpolate in the format argument, due to mismatch between the data encoding and the locale. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- gettext.c | 1 - t/t0203-gettext-setlocale-sanity.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100755 t/t0203-gettext-setlocale-sanity.sh diff --git a/gettext.c b/gettext.c index 7ae5caed42..db99742bc4 100644 --- a/gettext.c +++ b/gettext.c @@ -17,6 +17,5 @@ extern void git_setup_gettext(void) { } (void)setlocale(LC_MESSAGES, ""); - (void)setlocale(LC_CTYPE, ""); (void)textdomain("git"); } diff --git a/t/t0203-gettext-setlocale-sanity.sh b/t/t0203-gettext-setlocale-sanity.sh new file mode 100755 index 0000000000..a212460081 --- /dev/null +++ b/t/t0203-gettext-setlocale-sanity.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Copyright (c) 2010 Ævar Arnfjörð Bjarmason +# + +test_description="The Git C functions aren't broken by setlocale(3)" + +. ./lib-gettext.sh + +test_expect_success 'git show a ISO-8859-1 commit under C locale' ' + . "$TEST_DIRECTORY"/t3901-8859-1.txt && + test_commit "iso-c-commit" iso-under-c && + git show >out 2>err && + ! test -s err && + grep -q "iso-c-commit" out +' + +test_expect_success GETTEXT_LOCALE 'git show a ISO-8859-1 commit under a UTF-8 locale' ' + . "$TEST_DIRECTORY"/t3901-8859-1.txt && + test_commit "iso-utf8-commit" iso-under-utf8 && + LANGUAGE=is LC_ALL="$is_IS_locale" git show >out 2>err && + ! test -s err && + grep -q "iso-utf8-commit" out +' + +test_done From 44d3770f38f399962946f2a16e492a9d81c4665d Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Sun, 25 Jul 2010 16:55:46 +0200 Subject: [PATCH 1100/3720] tests: locate i18n lib&data correctly under --valgrind The new t020[01] for gettext support did not find git-sh-i18n and the translation data when run under --valgrind: lib-gettext.sh tried to locate them under $GIT_EXEC_PATH, which normally is the git build directory, but is changed by --valgrind to point to the wrappers. Introduce a new variable $GIT_BUILD_DIR which can be used to locate data that resides under the build directory, and use that instead. Signed-off-by: Thomas Rast Signed-off-by: Junio C Hamano --- t/lib-gettext.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh index 831ee38e83..f0cdd3da93 100644 --- a/t/lib-gettext.sh +++ b/t/lib-gettext.sh @@ -5,11 +5,11 @@ . ./test-lib.sh -GIT_TEXTDOMAINDIR="$GIT_EXEC_PATH/share/locale" -GIT_PO_PATH="$GIT_EXEC_PATH/po" +GIT_TEXTDOMAINDIR="$GIT_BUILD_DIR/share/locale" +GIT_PO_PATH="$GIT_BUILD_DIR/po" export GIT_TEXTDOMAINDIR GIT_PO_PATH -. "$GIT_EXEC_PATH"/git-sh-i18n +. "$GIT_BUILD_DIR"/git-sh-i18n if test_have_prereq GETTEXT then diff --git a/t/test-lib.sh b/t/test-lib.sh index 4ae0de8043..08e54386cb 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -768,6 +768,7 @@ else # normal case, use ../bin-wrappers only unless $with_dashes: PATH="$TEST_DIRECTORY/..:$PATH" fi fi +GIT_BUILD_DIR=$(pwd)/.. GIT_TEMPLATE_DIR=$(pwd)/../templates/blt unset GIT_CONFIG GIT_CONFIG_NOSYSTEM=1 From 267115871afe76dca10a4661287df55c8dd2dd42 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:37 +0800 Subject: [PATCH 1101/3720] Make graph_next_line external to other part of git We will use it in line level log output. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- graph.c | 13 +------------ graph.h | 11 +++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/graph.c b/graph.c index ac7c605406..47397daca3 100644 --- a/graph.c +++ b/graph.c @@ -7,17 +7,6 @@ /* Internal API */ -/* - * Output the next line for a graph. - * This formats the next graph line into the specified strbuf. It is not - * terminated with a newline. - * - * Returns 1 if the line includes the current commit, and 0 otherwise. - * graph_next_line() will return 1 exactly once for each time - * graph_update() is called. - */ -static int graph_next_line(struct git_graph *graph, struct strbuf *sb); - /* * Output a padding line in the graph. * This is similar to graph_next_line(). However, it is guaranteed to @@ -1143,7 +1132,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf graph_update_state(graph, GRAPH_PADDING); } -static int graph_next_line(struct git_graph *graph, struct strbuf *sb) +int graph_next_line(struct git_graph *graph, struct strbuf *sb) { switch (graph->state) { case GRAPH_PADDING: diff --git a/graph.h b/graph.h index b82ae87a49..f188168158 100644 --- a/graph.h +++ b/graph.h @@ -32,6 +32,17 @@ void graph_update(struct git_graph *graph, struct commit *commit); */ int graph_is_commit_finished(struct git_graph const *graph); +/* + * Output the next line for a graph. + * This formats the next graph line into the specified strbuf. It is not + * terminated with a newline. + * + * Returns 1 if the line includes the current commit, and 0 otherwise. + * graph_next_line() will return 1 exactly once for each time + * graph_update() is called. + */ +int graph_next_line(struct git_graph *graph, struct strbuf *sb); + /* * graph_show_*: helper functions for printing to stdout From 83361f5cde92e5cf77dbb63b5ff69b7e293bf117 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:38 +0800 Subject: [PATCH 1102/3720] Add parent rewriting to line history browser Walking forward through history (i.e., topologically earliest commits first), we filter the parent list of every commit as follows. Consider a parent P: - If P touches any of the interesting line ranges, we keep it. - If P is a merge and it takes all the interesting line ranges from one of its parents, P is rewritten to this parent, else we keep P. - Otherwise, P is rewritten to its (only) parent P^. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- line.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++----- line.h | 2 + revision.c | 3 + revision.h | 5 +- 4 files changed, 245 insertions(+), 27 deletions(-) diff --git a/line.c b/line.c index f059941bfd..58355b5734 100644 --- a/line.c +++ b/line.c @@ -9,8 +9,11 @@ #include "xdiff-interface.h" #include "strbuf.h" #include "log-tree.h" +#include "graph.h" #include "line.h" +static int limited; + static void cleanup(struct diff_line_range *r) { while (r) { @@ -389,6 +392,7 @@ struct diff_line_range *diff_line_range_clone(struct diff_line_range *r) struct diff_line_range *ret = xmalloc(sizeof(*ret)); int i = 0; + assert(r); DIFF_LINE_RANGE_INIT(ret); ret->ranges = xcalloc(r->nr, sizeof(struct line_range)); memcpy(ret->ranges, r->ranges, sizeof(struct line_range) * r->nr); @@ -469,14 +473,14 @@ void add_line_range(struct rev_info *revs, struct commit *commit, { struct diff_line_range *ret = NULL; - if (r != NULL) { - ret = lookup_decoration(&revs->line_range, &commit->object); - if (ret != NULL) - diff_line_range_merge(ret, r); - else - add_decoration(&revs->line_range, &commit->object, r); + ret = lookup_decoration(&revs->line_range, &commit->object); + if (ret != NULL && r != NULL) + diff_line_range_merge(ret, r); + else + add_decoration(&revs->line_range, &commit->object, r); + + if (r != NULL) commit->object.flags |= RANGE_UPDATE; - } } struct diff_line_range *lookup_line_range(struct rev_info *revs, @@ -550,6 +554,22 @@ void map_lines(long p_start, long p_end, long t_start, long t_end, return; } + if (start == t_start) { + *o_start = p_start; + *o_end = p_start + (end - start); + if (*o_end > p_end) + *o_end = p_end; + return; + } + + if (end == t_end) { + *o_start = p_end - (end - start); + if (*o_start < p_start) + *o_start = p_start; + *o_end = p_end; + return; + } + /* * A heuristic for lines mapping: * @@ -782,7 +802,7 @@ static void map_range_cb(void *data, long same, long p_next, long t_next) * to parents. * map_range_cb and map_range are used to map line ranges to the parent. */ -static void assign_range_to_parent(struct rev_info *rev, struct commit *c, +static int assign_range_to_parent(struct rev_info *rev, struct commit *c, struct commit *p, struct diff_line_range *r, struct diff_options *opt, int map) { @@ -930,9 +950,19 @@ static void assign_range_to_parent(struct rev_info *rev, struct commit *c, prev_r->next = NULL; } + if (!map) + goto out; + if (rr) { assert(p); add_line_range(rev, p, rr); + } else { + /* + * If there is no new ranges assigned to the parent, + * we should mark it as a 'root' commit. + */ + free(c->parents); + c->parents = NULL; } /* and the ranges of current commit c is updated */ @@ -940,10 +970,13 @@ static void assign_range_to_parent(struct rev_info *rev, struct commit *c, if (diff) c->object.flags |= NEED_PRINT; +out: if (tree1) free(tree1); if (tree2) free(tree2); + + return diff; } static void diff_update_parent_range(struct rev_info *rev, @@ -960,13 +993,21 @@ static void diff_update_parent_range(struct rev_info *rev, assign_range_to_parent(rev, commit, c, r, &rev->diffopt, 1); } +struct commit_state { + struct diff_line_range *range; + struct object obj; +}; + static void assign_parents_range(struct rev_info *rev, struct commit *commit) { struct commit_list *parents = commit->parents; struct diff_line_range *r = lookup_line_range(rev, commit); struct diff_line_range *evil = NULL, *range = NULL; + struct decoration parents_state; + struct commit_state *state = NULL; int nontrivial = 0; + memset(&parents_state, 0, sizeof(parents_state)); /* * If we are in linear history, update range and flush the patch if * necessary @@ -983,23 +1024,78 @@ static void assign_parents_range(struct rev_info *rev, struct commit *commit) parents = commit->parents; while (parents) { struct commit *p = parents->item; - assign_range_to_parent(rev, commit, p, r, &rev->diffopt, 1); + int diff = 0; + struct diff_line_range *origin_range = lookup_line_range(rev, p); + if (origin_range) + origin_range = diff_line_range_clone_deeply(origin_range); + + state = xmalloc(sizeof(*state)); + state->range = origin_range; + state->obj = p->object; + add_decoration(&parents_state, &p->object, state); + diff = assign_range_to_parent(rev, commit, p, r, &rev->diffopt, 1); + /* Since all the ranges comes from this parent, we can ignore others */ + if (diff == 0) { + /* restore the state of parents before this one */ + parents = commit->parents; + while (parents->item != p) { + struct commit_list *list = parents; + struct diff_line_range *line_range = NULL; + parents = parents->next; + line_range = lookup_line_range(rev, list->item); + cleanup(line_range); + state = lookup_decoration(&parents_state, &list->item->object); + add_decoration(&parents_state, &list->item->object, NULL); + add_line_range(rev, list->item, state->range); + list->item->object = state->obj; + free(state); + free(list); + } + + commit->parents = parents; + parents = parents->next; + commit->parents->next = NULL; + + /* free the non-use commit_list */ + while (parents) { + struct commit_list *list = parents; + parents = parents->next; + free(list); + } + goto out; + } + /* take the ranges from 'commit', try to detect nontrivial merge */ assign_range_to_parent(rev, commit, p, evil, &rev->diffopt, 0); parents = parents->next; } + commit->object.flags |= NONTRIVIAL_MERGE; /* * yes, this must be an evil merge. */ range = evil; while (range) { if (range->nr) { - commit->object.flags |= NEED_PRINT | EVIL_MERGE; + commit->object.flags |= EVIL_MERGE; nontrivial = 1; } range = range->next; } +out: + /* Never print out any diff for a merge commit */ + commit->object.flags &= ~NEED_PRINT; + + parents = commit->parents; + while (parents) { + state = lookup_decoration(&parents_state, &parents->item->object); + if (state) { + cleanup(state->range); + free(state); + } + parents = parents->next; + } + if (nontrivial) add_decoration(&rev->nontrivial_merge, &commit->object, evil); else @@ -1184,15 +1280,34 @@ static void diff_flush_filepair(struct rev_info *rev, struct diff_line_range *ra } #define EVIL_MERGE_STR "nontrivial merge found" -static void flush_nontrivial_merge(struct rev_info *rev, struct diff_line_range *range) +static void flush_nontrivial_merge(struct rev_info *rev, + struct diff_line_range *range) { struct diff_options *opt = &rev->diffopt; const char *reset = diff_get_color_opt(opt, DIFF_RESET); const char *frag = diff_get_color_opt(opt, DIFF_FRAGINFO); const char *meta = diff_get_color_opt(opt, DIFF_METAINFO); const char *new = diff_get_color_opt(opt, DIFF_FILE_NEW); + char *line_prefix = ""; + struct strbuf *msgbuf; + int evil = 0; + struct diff_line_range *r = range; - fprintf(opt->file, "%s%s%s\n", meta, EVIL_MERGE_STR, reset); + if (opt && opt->output_prefix) { + msgbuf = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = msgbuf->buf; + } + + while (r) { + if (r->nr) + evil = 1; + r = r->next; + } + + if (!evil) + return; + + fprintf(opt->file, "%s%s%s%s\n", line_prefix, meta, EVIL_MERGE_STR, reset); while (range) { if (range->nr) { @@ -1200,7 +1315,8 @@ static void flush_nontrivial_merge(struct rev_info *rev, struct diff_line_range const char *ptr = range->spec->data; const char *end = (const char *)range->spec->data + range->spec->size; int i = 0; - fprintf(opt->file, "%s%s%s\n\n", meta, range->spec->path, reset); + fprintf(opt->file, "%s%s%s%s\n", line_prefix, + meta, range->spec->path, reset); for (; i < range->nr; i++) { struct line_range *r = range->ranges + i; fprintf(opt->file, "%s@@ %ld,%ld @@%s\n", frag, r->start, @@ -1217,12 +1333,17 @@ static void flush_nontrivial_merge(struct rev_info *rev, struct diff_line_range static void line_log_flush(struct rev_info *rev, struct commit *c) { struct diff_line_range *range = lookup_line_range(rev, c); - struct diff_line_range *nontrivial = lookup_decoration(&rev->nontrivial_merge, &c->object); + struct diff_line_range *nontrivial = lookup_decoration(&rev->nontrivial_merge, + &c->object); struct log_info log; + struct diff_options *opt = &rev->diffopt; - if (range == NULL) + if (range == NULL || !(c->object.flags & NONTRIVIAL_MERGE || + c->object.flags & NEED_PRINT)) return; + if (rev->graph) + graph_update(rev->graph, c); log.commit = c; log.parent = NULL; rev->loginfo = &log; @@ -1234,13 +1355,21 @@ static void line_log_flush(struct rev_info *rev, struct commit *c) */ fprintf(rev->diffopt.file, "\n"); - if (c->object.flags & EVIL_MERGE) - return flush_nontrivial_merge(rev, nontrivial); + if (c->object.flags & NONTRIVIAL_MERGE) + flush_nontrivial_merge(rev, nontrivial); + else { + while (range) { + if (range->diff) + diff_flush_filepair(rev, range); + range = range->next; + } + } - while (range) { - if (range->diff) - diff_flush_filepair(rev, range); - range = range->next; + while (rev->graph && !graph_is_commit_finished(rev->graph)) { + struct strbuf sb; + strbuf_init(&sb, 0); + graph_next_line(rev->graph, &sb); + fputs(sb.buf, opt->file); } } @@ -1254,13 +1383,14 @@ int cmd_line_log_walk(struct rev_info *rev) die("revision walk prepare failed"); list = rev->commits; - if (list) { + if (list && !limited) { list->item->object.flags |= RANGE_UPDATE; list = list->next; } /* Clear the flags */ - while (list) { - list->item->object.flags &= ~(RANGE_UPDATE | EVIL_MERGE | NEED_PRINT); + while (list && !limited) { + list->item->object.flags &= ~(RANGE_UPDATE | NONTRIVIAL_MERGE | + NEED_PRINT | EVIL_MERGE); list = list->next; } @@ -1272,7 +1402,8 @@ int cmd_line_log_walk(struct rev_info *rev) if (commit->object.flags & RANGE_UPDATE) assign_parents_range(rev, commit); - if (commit->object.flags & NEED_PRINT) + if (commit->object.flags & NEED_PRINT || + commit->object.flags & NONTRIVIAL_MERGE || rev->graph) line_log_flush(rev, commit); r = lookup_line_range(rev, commit); @@ -1295,3 +1426,84 @@ int cmd_line_log_walk(struct rev_info *rev) return 0; } + +static enum rewrite_result rewrite_one(struct rev_info *rev, struct commit **pp) +{ + struct diff_line_range *r = NULL; + struct commit *p; + while (1) { + p = *pp; + if (p->object.flags & RANGE_UPDATE) + assign_parents_range(rev, p); + if (p->object.flags & NEED_PRINT || p->object.flags & NONTRIVIAL_MERGE) + return rewrite_one_ok; + if (!p->parents) + return rewrite_one_noparents; + + r = lookup_line_range(rev, p); + if (!r) + return rewrite_one_noparents; + *pp = p->parents->item; + } +} + +/* The rev->commits must be sorted in topologically order */ +void limit_list_line(struct rev_info *rev) +{ + struct commit_list *list = rev->commits; + struct commit_list *commits = xmalloc(sizeof(struct commit_list)); + struct commit_list *out = commits, *prev = commits; + struct commit *c; + struct diff_line_range *r; + + if (list) { + list->item->object.flags |= RANGE_UPDATE; + list = list->next; + } + /* Clear the flags */ + while (list) { + list->item->object.flags &= ~(RANGE_UPDATE | NONTRIVIAL_MERGE | + NEED_PRINT | EVIL_MERGE); + list = list->next; + } + + list = rev->commits; + while (list) { + c = list->item; + + if (c->object.flags & RANGE_UPDATE) + assign_parents_range(rev, c); + + if (c->object.flags & NEED_PRINT || c->object.flags & NONTRIVIAL_MERGE) { + if (rewrite_parents(rev, c, rewrite_one)) + die("Can't rewrite parent for commit %s", + sha1_to_hex(c->object.sha1)); + commits->item = c; + commits->next = xmalloc(sizeof(struct commit_list)); + prev = commits; + commits = commits->next; + } else { + r = lookup_line_range(rev, c); + if (r) { + cleanup(r); + r = NULL; + add_line_range(rev, c, r); + } + } + + list = list->next; + } + + prev->next = NULL; + free(commits); + + list = rev->commits; + while (list) { + struct commit_list *l = list; + list = list->next; + free(l); + } + + rev->commits = out; + limited = 1; +} diff --git a/line.h b/line.h index 202130fa12..c00f1e6024 100644 --- a/line.h +++ b/line.h @@ -136,4 +136,6 @@ const char *parse_loc(const char *spec, nth_line_fn_t nth_line, extern int cmd_line_log_walk(struct rev_info *rev); +extern void limit_list_line(struct rev_info *rev); + #endif diff --git a/revision.c b/revision.c index fb089784e9..a6527ca1ed 100644 --- a/revision.c +++ b/revision.c @@ -13,6 +13,7 @@ #include "decorate.h" #include "log-tree.h" #include "string-list.h" +#include "line.h" volatile show_early_output_fn_t show_early_output; @@ -1886,6 +1887,8 @@ int prepare_revision_walk(struct rev_info *revs) return -1; if (revs->topo_order) sort_in_topological_order(&revs->commits, revs->lifo); + if (revs->rewrite_parents && revs->line_level_traverse) + limit_list_line(revs); if (revs->simplify_merges) simplify_merges(revs); if (revs->children.name) diff --git a/revision.h b/revision.h index 48222f678f..7f7d17810a 100644 --- a/revision.h +++ b/revision.h @@ -16,8 +16,9 @@ #define SYMMETRIC_LEFT (1u<<8) #define RANGE_UPDATE (1u<<9) /* for line level traverse */ #define NEED_PRINT (1u<<10) -#define EVIL_MERGE (1u<<11) -#define ALL_REV_FLAGS ((1u<<12)-1) +#define NONTRIVIAL_MERGE (1u<<11) +#define EVIL_MERGE (1u<<12) +#define ALL_REV_FLAGS ((1u<<13)-1) #define DECORATE_SHORT_REFS 1 #define DECORATE_FULL_REFS 2 From f97683ba1ecb1e6c9c1652dac4accaf5055ee346 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:39 +0800 Subject: [PATCH 1103/3720] Add --graph prefix before line history output Makes the line level log output look good when used with the '--graph' option. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- line.c | 66 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/line.c b/line.c index 58355b5734..5b1d889e23 100644 --- a/line.c +++ b/line.c @@ -1115,6 +1115,13 @@ static void flush_lines(struct diff_options *opt, const char **ptr, const char * const char *p = *ptr; struct strbuf buf = STRBUF_INIT; const char *reset; + char *line_prefix = ""; + struct strbuf *msgbuf; + + if (opt && opt->output_prefix) { + msgbuf = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = msgbuf->buf; + } if (*color) reset = diff_get_color_opt(opt, DIFF_RESET); @@ -1137,7 +1144,7 @@ static void flush_lines(struct diff_options *opt, const char **ptr, const char * while (*ptr < end && *lno <= elno) { if (**ptr == '\n') { - fprintf(opt->file, "%s", buf.buf); + fprintf(opt->file, "%s%s", line_prefix, buf.buf); if (*ptr - p) fwrite(p, *ptr - p, 1, opt->file); fprintf(opt->file, "%s\n", reset); @@ -1147,7 +1154,7 @@ static void flush_lines(struct diff_options *opt, const char **ptr, const char * (*ptr)++; } if (*lno <= elno) { - fprintf(opt->file, "%s", buf.buf); + fprintf(opt->file, "%s%s", line_prefix, buf.buf); if (*ptr - p) fwrite(p, *ptr - p, 1, opt->file); fprintf(opt->file, "%s\n", reset); @@ -1189,8 +1196,15 @@ static void diff_flush_chunks(struct diff_options *opt, struct line_chunk *chunk struct diff_line_range *range = chunk->range; const char *set = diff_get_color_opt(opt, DIFF_FRAGINFO); const char *reset = diff_get_color_opt(opt, DIFF_RESET); + char *line_prefix = ""; + struct strbuf *msgbuf; int i; + if (opt && opt->output_prefix) { + msgbuf = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = msgbuf->buf; + } + for (i = 0; i < range->nr; i++) { struct line_range *r = range->ranges + i; long lenp = r->pend - r->pstart + 1, pstart = r->pstart; @@ -1198,8 +1212,8 @@ static void diff_flush_chunks(struct diff_options *opt, struct line_chunk *chunk if (pstart == 0) lenp = 0; - fprintf(opt->file, "%s@@ -%ld,%ld +%ld,%ld @@%s\n", - set, pstart, lenp, r->start, len, reset); + fprintf(opt->file, "%s%s@@ -%ld,%ld +%ld,%ld @@%s\n", + line_prefix, set, pstart, lenp, r->start, len, reset); diff_flush_range(opt, chunk, r); } @@ -1218,6 +1232,13 @@ static void diff_flush_filepair(struct rev_info *rev, struct diff_line_range *ra const char *reset = diff_get_color_opt(opt, DIFF_RESET); struct line_chunk chunk; int must_show_header; + char *line_prefix = ""; + struct strbuf *msgbuf; + + if (opt && opt->output_prefix) { + msgbuf = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = msgbuf->buf; + } /* * the ranges that touch no different file, in this case @@ -1251,21 +1272,26 @@ static void diff_flush_filepair(struct rev_info *rev, struct diff_line_range *ra b_two = quote_two(b_prefix, name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; - strbuf_addf(&header, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset); + strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, + set, a_one, b_two, reset); if (lbl[0][0] == '/') { - strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset); + strbuf_addf(&header, "%s%snew file mode %06o%s\n", + line_prefix, set, two->mode, reset); } else if (lbl[1][0] == '/') { - strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset); + strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", + line_prefix, set, one->mode, reset); } else if (one->mode != two->mode) { - strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset); - strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset); + strbuf_addf(&header, "%s%sold mode %06o%s\n", + line_prefix, set, one->mode, reset); + strbuf_addf(&header, "%s%snew mode %06o%s\n", + line_prefix, set, two->mode, reset); } fprintf(opt->file, "%s%s", header.buf, meta.buf); strbuf_release(&meta); strbuf_release(&header); - fprintf(opt->file, "%s--- %s%s\n", set, lbl[0], reset); - fprintf(opt->file, "%s+++ %s%s\n", set, lbl[1], reset); + fprintf(opt->file, "%s%s--- %s%s\n", line_prefix, set, lbl[0], reset); + fprintf(opt->file, "%s%s+++ %s%s\n", line_prefix, set, lbl[1], reset); free((void *)a_one); free((void *)b_two); @@ -1319,12 +1345,13 @@ static void flush_nontrivial_merge(struct rev_info *rev, meta, range->spec->path, reset); for (; i < range->nr; i++) { struct line_range *r = range->ranges + i; - fprintf(opt->file, "%s@@ %ld,%ld @@%s\n", frag, r->start, + fprintf(opt->file, "%s%s@@ %ld,%ld @@%s\n", + line_prefix, frag, r->start, r->end - r->start + 1, reset); flush_lines(opt, &ptr, end, r->start, r->end, &lno, new, ' '); } - fprintf(opt->file, "\n"); + fprintf(opt->file, "%s\n", line_prefix); } range = range->next; } @@ -1337,6 +1364,8 @@ static void line_log_flush(struct rev_info *rev, struct commit *c) &c->object); struct log_info log; struct diff_options *opt = &rev->diffopt; + char *line_prefix = ""; + struct strbuf *msgbuf; if (range == NULL || !(c->object.flags & NONTRIVIAL_MERGE || c->object.flags & NEED_PRINT)) @@ -1349,11 +1378,12 @@ static void line_log_flush(struct rev_info *rev, struct commit *c) rev->loginfo = &log; show_log(rev); rev->loginfo = NULL; - /* - * Add a new line after each commit message, of course we should - * add --graph alignment later when the patches comes to master. - */ - fprintf(rev->diffopt.file, "\n"); + + if (opt && opt->output_prefix) { + msgbuf = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = msgbuf->buf; + } + fprintf(rev->diffopt.file, "%s\n", line_prefix); if (c->object.flags & NONTRIVIAL_MERGE) flush_nontrivial_merge(rev, nontrivial); From 1d82bbf3159b1b9dd206a0b6a9ac7ec26f748b49 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:40 +0800 Subject: [PATCH 1104/3720] Add --full-line-diff option Always print the interesting ranges even if the current commit does not change any line of it. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- builtin/log.c | 8 +++++++- line.c | 22 ++++++++++++++++------ revision.c | 5 ++++- revision.h | 3 ++- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index 637bceafc4..0151d2f4b6 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -85,6 +85,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, { int i; int decoration_given = 0; + static int full_line_diff; struct userformat_want w; const char *path = NULL, *fullpath = NULL; static struct diff_line_range *range; @@ -95,6 +96,9 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, OPT_CALLBACK('L', NULL, &line_cb, "n,m", "Process only line range n,m, counting from 1", log_line_range_callback), + OPT_BOOLEAN(0, "full-line-diff", &full_line_diff, + "Always print the interesting range even if the \ + current commit does not change any line of it"), OPT_END() }; @@ -223,8 +227,10 @@ parse_done: } /* Test whether line level history is asked for */ - if (range && range->nr > 0) + if (range && range->nr > 0) { setup_line(rev, range); + rev->full_line_diff = full_line_diff; + } } /* diff --git a/line.c b/line.c index 5b1d889e23..63dd19a8c4 100644 --- a/line.c +++ b/line.c @@ -1243,10 +1243,18 @@ static void diff_flush_filepair(struct rev_info *rev, struct diff_line_range *ra /* * the ranges that touch no different file, in this case * the line number will not change, and of course we have - * no sensible rang->pair since there is no diff run. + * no sensible range->pair since there is no diff run. */ - if (one == NULL) + if (one == NULL) { + if (rev->full_line_diff) { + chunk.two = two->data; + chunk.two_end = (const char *)two->data + two->size; + chunk.ltwo = 1; + chunk.range = range; + diff_flush_chunks(&rev->diffopt, &chunk); + } return; + } if (range->status == DIFF_STATUS_DELETED) die("We are following an nonexistent file, interesting!"); @@ -1368,7 +1376,8 @@ static void line_log_flush(struct rev_info *rev, struct commit *c) struct strbuf *msgbuf; if (range == NULL || !(c->object.flags & NONTRIVIAL_MERGE || - c->object.flags & NEED_PRINT)) + c->object.flags & NEED_PRINT || + rev->full_line_diff)) return; if (rev->graph) @@ -1389,7 +1398,7 @@ static void line_log_flush(struct rev_info *rev, struct commit *c) flush_nontrivial_merge(rev, nontrivial); else { while (range) { - if (range->diff) + if (range->diff || (range->nr && rev->full_line_diff)) diff_flush_filepair(rev, range); range = range->next; } @@ -1420,7 +1429,7 @@ int cmd_line_log_walk(struct rev_info *rev) /* Clear the flags */ while (list && !limited) { list->item->object.flags &= ~(RANGE_UPDATE | NONTRIVIAL_MERGE | - NEED_PRINT | EVIL_MERGE); + NEED_PRINT | EVIL_MERGE); list = list->next; } @@ -1433,7 +1442,8 @@ int cmd_line_log_walk(struct rev_info *rev) assign_parents_range(rev, commit); if (commit->object.flags & NEED_PRINT || - commit->object.flags & NONTRIVIAL_MERGE || rev->graph) + commit->object.flags & NONTRIVIAL_MERGE || + rev->full_line_diff) line_log_flush(rev, commit); r = lookup_line_range(rev, commit); diff --git a/revision.c b/revision.c index a6527ca1ed..62fe002528 100644 --- a/revision.c +++ b/revision.c @@ -1887,7 +1887,10 @@ int prepare_revision_walk(struct rev_info *revs) return -1; if (revs->topo_order) sort_in_topological_order(&revs->commits, revs->lifo); - if (revs->rewrite_parents && revs->line_level_traverse) + if (revs->full_line_diff) + revs->dense = 0; + if (revs->rewrite_parents && revs->line_level_traverse + && !revs->full_line_diff) limit_list_line(revs); if (revs->simplify_merges) simplify_merges(revs); diff --git a/revision.h b/revision.h index 7f7d17810a..db901e5686 100644 --- a/revision.h +++ b/revision.h @@ -73,7 +73,8 @@ struct rev_info { bisect:1, ancestry_path:1, first_parent_only:1, - line_level_traverse:1; + line_level_traverse:1, + full_line_diff:1; /* Diff flags */ unsigned int diff:1, From 83c0e5ad8ce526543d0aacc82352b511a6eb3ec5 Mon Sep 17 00:00:00 2001 From: Joshua Jensen Date: Mon, 16 Aug 2010 21:38:09 +0200 Subject: [PATCH 1105/3720] Add string comparison functions that respect the ignore_case variable. Multiple locations within this patch series alter a case sensitive string comparison call such as strcmp() to be a call to a string comparison call that selects case comparison based on the global ignore_case variable. Behaviorally, when core.ignorecase=false, the *_icase() versions are functionally equivalent to their C runtime counterparts. When core.ignorecase=true, the *_icase() versions perform a case insensitive comparison. Like Linus' earlier ignorecase patch, these may ignore filename conventions on certain file systems. By isolating filename comparisons to certain functions, support for those filename conventions may be more easily met. Signed-off-by: Joshua Jensen Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- dir.c | 16 ++++++++++++++++ dir.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/dir.c b/dir.c index 133f472a1e..4d001fd632 100644 --- a/dir.c +++ b/dir.c @@ -18,6 +18,22 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, in int check_only, const struct path_simplify *simplify); static int get_dtype(struct dirent *de, const char *path, int len); +/* helper string functions with support for the ignore_case flag */ +int strcmp_icase(const char *a, const char *b) +{ + return ignore_case ? strcasecmp(a, b) : strcmp(a, b); +} + +int strncmp_icase(const char *a, const char *b, size_t count) +{ + return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count); +} + +int fnmatch_icase(const char *pattern, const char *string, int flags) +{ + return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0)); +} + static int common_prefix(const char **pathspec) { const char *path, *slash, *next; diff --git a/dir.h b/dir.h index 278d84cdf7..b3e2104b9f 100644 --- a/dir.h +++ b/dir.h @@ -101,4 +101,8 @@ extern int remove_dir_recursively(struct strbuf *path, int flag); /* tries to remove the path with empty directories along it, ignores ENOENT */ extern int remove_path(const char *path); +extern int strcmp_icase(const char *a, const char *b); +extern int strncmp_icase(const char *a, const char *b, size_t count); +extern int fnmatch_icase(const char *pattern, const char *string, int flags); + #endif From c374b04bee1d4bfd3f742fbb3a55ea57209a1cf6 Mon Sep 17 00:00:00 2001 From: Joshua Jensen Date: Mon, 16 Aug 2010 21:38:10 +0200 Subject: [PATCH 1106/3720] Case insensitivity support for .gitignore via core.ignorecase This is especially beneficial when using Windows and Perforce and the git-p4 bridge. Internally, Perforce preserves a given file's full path including its case at the time it was added to the Perforce repository. When syncing a file down via Perforce, missing directories are created, if necessary, using the case as stored with the filename. Unfortunately, two files in the same directory can have differing cases for their respective paths, such as /diRa/file1.c and /DirA/file2.c. Depending on sync order, DirA/ may get created instead of diRa/. It is possible to handle directory names in a case insensitive manner without this patch, but it is highly inconvenient, requiring each character to be specified like so: [Bb][Uu][Ii][Ll][Dd]. With this patch, the gitignore exclusions honor the core.ignorecase=true configuration setting and make the process less error prone. The above is specified like so: Build Signed-off-by: Joshua Jensen Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- dir.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dir.c b/dir.c index 4d001fd632..be21c201ab 100644 --- a/dir.c +++ b/dir.c @@ -390,14 +390,14 @@ int excluded_from_list(const char *pathname, if (x->flags & EXC_FLAG_NODIR) { /* match basename */ if (x->flags & EXC_FLAG_NOWILDCARD) { - if (!strcmp(exclude, basename)) + if (!strcmp_icase(exclude, basename)) return to_exclude; } else if (x->flags & EXC_FLAG_ENDSWITH) { if (x->patternlen - 1 <= pathlen && - !strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1)) + !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1)) return to_exclude; } else { - if (fnmatch(exclude, basename, 0) == 0) + if (fnmatch_icase(exclude, basename, 0) == 0) return to_exclude; } } @@ -412,14 +412,14 @@ int excluded_from_list(const char *pathname, if (pathlen < baselen || (baselen && pathname[baselen-1] != '/') || - strncmp(pathname, x->base, baselen)) + strncmp_icase(pathname, x->base, baselen)) continue; if (x->flags & EXC_FLAG_NOWILDCARD) { - if (!strcmp(exclude, pathname + baselen)) + if (!strcmp_icase(exclude, pathname + baselen)) return to_exclude; } else { - if (fnmatch(exclude, pathname+baselen, + if (fnmatch_icase(exclude, pathname+baselen, FNM_PATHNAME) == 0) return to_exclude; } From eeecf0bc5bc5c7e518d8a7b7ff0d92eaa30e09e3 Mon Sep 17 00:00:00 2001 From: Joshua Jensen Date: Mon, 16 Aug 2010 21:38:11 +0200 Subject: [PATCH 1107/3720] Add case insensitivity support for directories when using git status When using a case preserving but case insensitive file system, directory case can differ but still refer to the same physical directory. git status reports the directory with the alternate case as an Untracked file. (That is, when mydir/filea.txt is added to the repository and then the directory on disk is renamed from mydir/ to MyDir/, git status shows MyDir/ as being untracked.) Support has been added in name-hash.c for hashing directories with a terminating slash into the name hash. When index_name_exists() is called with a directory (a name with a terminating slash), the name is not found via the normal cache_name_compare() call, but it is found in the slow_same_name() function. Additionally, in dir.c, directory_exists_in_index_icase() allows newly added directories deeper in the directory chain to be identified. Ultimately, it would be better if the file list was read in case insensitive alphabetical order from disk, but this change seems to suffice for now. The end result is the directory is looked up in a case insensitive manner and does not show in the Untracked files list. Signed-off-by: Joshua Jensen Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- dir.c | 40 ++++++++++++++++++++++++++++- name-hash.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/dir.c b/dir.c index be21c201ab..ee80204421 100644 --- a/dir.c +++ b/dir.c @@ -484,6 +484,39 @@ enum exist_status { index_gitdir }; +/* + * Do not use the alphabetically stored index to look up + * the directory name; instead, use the case insensitive + * name hash. + */ +static enum exist_status directory_exists_in_index_icase(const char *dirname, int len) +{ + struct cache_entry *ce = index_name_exists(&the_index, dirname, len + 1, ignore_case); + unsigned char endchar; + + if (!ce) + return index_nonexistent; + endchar = ce->name[len]; + + /* + * The cache_entry structure returned will contain this dirname + * and possibly additional path components. + */ + if (endchar == '/') + return index_directory; + + /* + * If there are no additional path components, then this cache_entry + * represents a submodule. Submodules, despite being directories, + * are stored in the cache without a closing slash. + */ + if (!endchar && S_ISGITLINK(ce->ce_mode)) + return index_gitdir; + + /* This should never be hit, but it exists just in case. */ + return index_nonexistent; +} + /* * The index sorts alphabetically by entry name, which * means that a gitlink sorts as '\0' at the end, while @@ -493,7 +526,12 @@ enum exist_status { */ static enum exist_status directory_exists_in_index(const char *dirname, int len) { - int pos = cache_name_pos(dirname, len); + int pos; + + if (ignore_case) + return directory_exists_in_index_icase(dirname, len); + + pos = cache_name_pos(dirname, len); if (pos < 0) pos = -pos-1; while (pos < active_nr) { diff --git a/name-hash.c b/name-hash.c index 0031d78e8c..c6b6a3fe4c 100644 --- a/name-hash.c +++ b/name-hash.c @@ -32,6 +32,42 @@ static unsigned int hash_name(const char *name, int namelen) return hash; } +static void hash_index_entry_directories(struct index_state *istate, struct cache_entry *ce) +{ + /* + * Throw each directory component in the hash for quick lookup + * during a git status. Directory components are stored with their + * closing slash. Despite submodules being a directory, they never + * reach this point, because they are stored without a closing slash + * in the cache. + * + * Note that the cache_entry stored with the directory does not + * represent the directory itself. It is a pointer to an existing + * filename, and its only purpose is to represent existence of the + * directory in the cache. It is very possible multiple directory + * hash entries may point to the same cache_entry. + */ + unsigned int hash; + void **pos; + + const char *ptr = ce->name; + while (*ptr) { + while (*ptr && *ptr != '/') + ++ptr; + if (*ptr == '/') { + ++ptr; + hash = hash_name(ce->name, ptr - ce->name); + if (!lookup_hash(hash, &istate->name_hash)) { + pos = insert_hash(hash, ce, &istate->name_hash); + if (pos) { + ce->next = *pos; + *pos = ce; + } + } + } + } +} + static void hash_index_entry(struct index_state *istate, struct cache_entry *ce) { void **pos; @@ -47,6 +83,9 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce) ce->next = *pos; *pos = ce; } + + if (ignore_case) + hash_index_entry_directories(istate, ce); } static void lazy_init_name_hash(struct index_state *istate) @@ -97,7 +136,21 @@ static int same_name(const struct cache_entry *ce, const char *name, int namelen if (len == namelen && !cache_name_compare(name, namelen, ce->name, len)) return 1; - return icase && slow_same_name(name, namelen, ce->name, len); + if (!icase) + return 0; + + /* + * If the entry we're comparing is a filename (no trailing slash), then compare + * the lengths exactly. + */ + if (name[namelen - 1] != '/') + return slow_same_name(name, namelen, ce->name, len); + + /* + * For a directory, we point to an arbitrary cache_entry filename. Just + * make sure the directory portion matches. + */ + return slow_same_name(name, namelen, ce->name, namelen < len ? namelen : len); } struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase) @@ -115,5 +168,22 @@ struct cache_entry *index_name_exists(struct index_state *istate, const char *na } ce = ce->next; } + + /* + * Might be a submodule. Despite submodules being directories, + * they are stored in the name hash without a closing slash. + * When ignore_case is 1, directories are stored in the name hash + * with their closing slash. + * + * The side effect of this storage technique is we have need to + * remove the slash from name and perform the lookup again without + * the slash. If a match is made, S_ISGITLINK(ce->mode) will be + * true. + */ + if (icase && name[namelen - 1] == '/') { + ce = index_name_exists(istate, name, namelen - 1, icase); + if (ce && S_ISGITLINK(ce->ce_mode)) + return ce; + } return NULL; } From 2a1da2706148f9fe9b9d1f8204c219bf7121ed76 Mon Sep 17 00:00:00 2001 From: Joshua Jensen Date: Mon, 16 Aug 2010 21:38:12 +0200 Subject: [PATCH 1108/3720] Add case insensitivity support when using git ls-files When mydir/filea.txt is added, mydir/ is renamed to MyDir/, and MyDir/fileb.txt is added, running git ls-files mydir only shows mydir/filea.txt. Running git ls-files MyDir shows MyDir/fileb.txt. Running git ls-files mYdIR shows nothing. With this patch running git ls-files for mydir, MyDir, and mYdIR shows mydir/filea.txt and MyDir/fileb.txt. Wildcards are not handled case insensitively in this patch. Example: MyDir/aBc/file.txt is added. git ls-files MyDir/a* works fine, but git ls-files mydir/a* does not. Signed-off-by: Joshua Jensen Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- dir.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/dir.c b/dir.c index ee80204421..58ec1a11d9 100644 --- a/dir.c +++ b/dir.c @@ -107,16 +107,30 @@ static int match_one(const char *match, const char *name, int namelen) if (!*match) return MATCHED_RECURSIVELY; - for (;;) { - unsigned char c1 = *match; - unsigned char c2 = *name; - if (c1 == '\0' || is_glob_special(c1)) - break; - if (c1 != c2) - return 0; - match++; - name++; - namelen--; + if (ignore_case) { + for (;;) { + unsigned char c1 = tolower(*match); + unsigned char c2 = tolower(*name); + if (c1 == '\0' || is_glob_special(c1)) + break; + if (c1 != c2) + return 0; + match++; + name++; + namelen--; + } + } else { + for (;;) { + unsigned char c1 = *match; + unsigned char c2 = *name; + if (c1 == '\0' || is_glob_special(c1)) + break; + if (c1 != c2) + return 0; + match++; + name++; + namelen--; + } } @@ -125,8 +139,8 @@ static int match_one(const char *match, const char *name, int namelen) * we need to match by fnmatch */ matchlen = strlen(match); - if (strncmp(match, name, matchlen)) - return !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0; + if (strncmp_icase(match, name, matchlen)) + return !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0; if (namelen == matchlen) return MATCHED_EXACTLY; From a91604c1dfd642fb9edcc424134c9695ad03fe52 Mon Sep 17 00:00:00 2001 From: Joshua Jensen Date: Mon, 16 Aug 2010 21:38:13 +0200 Subject: [PATCH 1109/3720] Support case folding for git add when core.ignorecase=true When MyDir/ABC/filea.txt is added to Git, the disk directory MyDir/ABC/ is renamed to mydir/aBc/, and then mydir/aBc/fileb.txt is added, the index will contain MyDir/ABC/filea.txt and mydir/aBc/fileb.txt. Although the earlier portions of this patch series account for those differences in case, this patch makes the pathing consistent by folding the case of newly added files against the first file added with that path. In read-cache.c's add_to_index(), the index_name_exists() support used for git status's case insensitive directory lookups is used to find the proper directory case according to what the user already checked in. That is, MyDir/ABC/'s case is used to alter the stored path for fileb.txt to MyDir/ABC/fileb.txt (instead of mydir/aBc/fileb.txt). This is especially important when cloning a repository to a case sensitive file system. MyDir/ABC/ and mydir/aBc/ exist in the same directory on a Windows machine, but on Linux, the files exist in two separate directories. The update to add_to_index(), in effect, treats a Windows file system as case sensitive by making path case consistent. Signed-off-by: Joshua Jensen Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- read-cache.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/read-cache.c b/read-cache.c index f1f789b7b8..ae1366a329 100644 --- a/read-cache.c +++ b/read-cache.c @@ -608,6 +608,29 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, ce->ce_mode = ce_mode_from_stat(ent, st_mode); } + /* When core.ignorecase=true, determine if a directory of the same name but differing + * case already exists within the Git repository. If it does, ensure the directory + * case of the file being added to the repository matches (is folded into) the existing + * entry's directory case. + */ + if (ignore_case) { + const char *startPtr = ce->name; + const char *ptr = startPtr; + while (*ptr) { + while (*ptr && *ptr != '/') + ++ptr; + if (*ptr == '/') { + struct cache_entry *foundce; + ++ptr; + foundce = index_name_exists(&the_index, ce->name, ptr - ce->name, ignore_case); + if (foundce) { + memcpy((void*)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr); + startPtr = ptr; + } + } + } + } + alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case); if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) { /* Nothing changed, really */ From ac1c80f7645b6fa90534890e1f83005d40d98281 Mon Sep 17 00:00:00 2001 From: Joshua Jensen Date: Mon, 16 Aug 2010 21:38:14 +0200 Subject: [PATCH 1110/3720] Support case folding in git fast-import when core.ignorecase=true When core.ignorecase=true, imported file paths will be folded to match existing directory case. Signed-off-by: Joshua Jensen Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- fast-import.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fast-import.c b/fast-import.c index ddad289dae..c3abe554cb 100644 --- a/fast-import.c +++ b/fast-import.c @@ -156,6 +156,7 @@ Format of STDIN stream: #include "csum-file.h" #include "quote.h" #include "exec_cmd.h" +#include "dir.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1<entry_count; i++) { e = t->entries[i]; - if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) { + if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) { if (!slash1) { if (!S_ISDIR(mode) && e->versions[1].mode == mode @@ -1527,7 +1528,7 @@ static int tree_content_remove( for (i = 0; i < t->entry_count; i++) { e = t->entries[i]; - if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) { + if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) { if (!slash1 || !S_ISDIR(e->versions[1].mode)) goto del_entry; if (!e->tree) @@ -1577,7 +1578,7 @@ static int tree_content_get( for (i = 0; i < t->entry_count; i++) { e = t->entries[i]; - if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) { + if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) { if (!slash1) { memcpy(leaf, e, sizeof(*leaf)); if (e->tree && is_null_sha1(e->versions[1].sha1)) From 76c77279b41cad3819e56858882d1d4758f8cb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 19 Aug 2010 16:08:09 +0000 Subject: [PATCH 1111/3720] test-lib: Use $TEST_DIRECTORY or $GIT_BUILD_DIR instead of $(pwd) and ../ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the redundant calls to $(pwd) to use $TEST_DIRECTORY instead. None of these were being executed after we cd'd somewhere else so they weren't actually needed. This also makes it easier to add support for overriding the test library location and run tests in a different directory than t/. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- t/test-lib.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index ab4c96788e..9face09c94 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -794,14 +794,14 @@ else # normal case, use ../bin-wrappers only unless $with_dashes: PATH="$TEST_DIRECTORY/..:$PATH" fi fi -GIT_BUILD_DIR=$(pwd)/.. -GIT_TEMPLATE_DIR=$(pwd)/../templates/blt +GIT_BUILD_DIR="$TEST_DIRECTORY"/.. +GIT_TEMPLATE_DIR="$TEST_DIRECTORY"/../templates/blt unset GIT_CONFIG GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_NOGLOBAL=1 export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL -. ../GIT-BUILD-OPTIONS +. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS if test -z "$GIT_TEST_CMP" then @@ -813,22 +813,22 @@ then fi fi -GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git +GITPERLLIB="$TEST_DIRECTORY"/../perl/blib/lib:"$TEST_DIRECTORY"/../perl/blib/arch/auto/Git export GITPERLLIB -test -d ../templates/blt || { +test -d "$TEST_DIRECTORY"/../templates/blt || { error "You haven't built things yet, have you?" } if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON" then - GITPYTHONLIB="$(pwd)/../git_remote_helpers/build/lib" + GITPYTHONLIB="$TEST_DIRECTORY/../git_remote_helpers/build/lib" export GITPYTHONLIB - test -d ../git_remote_helpers/build || { + test -d "$TEST_DIRECTORY"/../git_remote_helpers/build || { error "You haven't built git_remote_helpers yet, have you?" } fi -if ! test -x ../test-chmtime; then +if ! test -x "$TEST_DIRECTORY"/../test-chmtime; then echo >&2 'You need to build test-chmtime:' echo >&2 'Run "make test-chmtime" in the source (toplevel) directory' exit 1 From e4b52593c67d5ce2710158a6bece402fe110cade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 19 Aug 2010 16:08:10 +0000 Subject: [PATCH 1112/3720] test-lib: Use "$GIT_BUILD_DIR" instead of "$TEST_DIRECTORY"/../ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change code that used $TEST_DIRECTORY/.. to use $GIT_BUILD_DIR instead, the two are equivalent, but the latter is easier to read. This required moving the assignment od GIT_BUILD_DIR to earlier in the test-lib.sh file. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- t/test-lib.sh | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 9face09c94..9c089677fb 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -649,7 +649,7 @@ test_create_repo () { repo="$1" mkdir -p "$repo" cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git-init" "--template=$TEST_DIRECTORY/../templates/blt/" >&3 2>&4 || + "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || error "cannot run git init -- have you built things yet?" mv .git/hooks .git/hooks-disabled cd "$owd" @@ -712,6 +712,8 @@ test_done () { # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. TEST_DIRECTORY=$(pwd) +GIT_BUILD_DIR="$TEST_DIRECTORY"/.. + if test -n "$valgrind" then make_symlink () { @@ -738,7 +740,7 @@ then test -x "$1" || return base=$(basename "$1") - symlink_target=$TEST_DIRECTORY/../$base + symlink_target=$GIT_BUILD_DIR/$base # do not override scripts if test -x "$symlink_target" && test ! -d "$symlink_target" && @@ -757,7 +759,7 @@ then # override all git executables in TEST_DIRECTORY/.. GIT_VALGRIND=$TEST_DIRECTORY/valgrind mkdir -p "$GIT_VALGRIND"/bin - for file in $TEST_DIRECTORY/../git* $TEST_DIRECTORY/../test-* + for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-* do make_valgrind_symlink $file done @@ -778,10 +780,10 @@ then elif test -n "$GIT_TEST_INSTALLED" ; then GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) || error "Cannot run git from $GIT_TEST_INSTALLED." - PATH=$GIT_TEST_INSTALLED:$TEST_DIRECTORY/..:$PATH + PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR:$PATH GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH} else # normal case, use ../bin-wrappers only unless $with_dashes: - git_bin_dir="$TEST_DIRECTORY/../bin-wrappers" + git_bin_dir="$GIT_BUILD_DIR/bin-wrappers" if ! test -x "$git_bin_dir/git" ; then if test -z "$with_dashes" ; then say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH" @@ -789,13 +791,12 @@ else # normal case, use ../bin-wrappers only unless $with_dashes: with_dashes=t fi PATH="$git_bin_dir:$PATH" - GIT_EXEC_PATH=$TEST_DIRECTORY/.. + GIT_EXEC_PATH=$GIT_BUILD_DIR if test -n "$with_dashes" ; then - PATH="$TEST_DIRECTORY/..:$PATH" + PATH="$GIT_BUILD_DIR:$PATH" fi fi -GIT_BUILD_DIR="$TEST_DIRECTORY"/.. -GIT_TEMPLATE_DIR="$TEST_DIRECTORY"/../templates/blt +GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt unset GIT_CONFIG GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_NOGLOBAL=1 @@ -813,22 +814,22 @@ then fi fi -GITPERLLIB="$TEST_DIRECTORY"/../perl/blib/lib:"$TEST_DIRECTORY"/../perl/blib/arch/auto/Git +GITPERLLIB="$GIT_BUILD_DIR"/perl/blib/lib:"$GIT_BUILD_DIR"/perl/blib/arch/auto/Git export GITPERLLIB -test -d "$TEST_DIRECTORY"/../templates/blt || { +test -d "$GIT_BUILD_DIR"/templates/blt || { error "You haven't built things yet, have you?" } if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON" then - GITPYTHONLIB="$TEST_DIRECTORY/../git_remote_helpers/build/lib" + GITPYTHONLIB="$GIT_BUILD_DIR/git_remote_helpers/build/lib" export GITPYTHONLIB - test -d "$TEST_DIRECTORY"/../git_remote_helpers/build || { + test -d "$GIT_BUILD_DIR"/git_remote_helpers/build || { error "You haven't built git_remote_helpers yet, have you?" } fi -if ! test -x "$TEST_DIRECTORY"/../test-chmtime; then +if ! test -x "$GIT_BUILD_DIR"/test-chmtime; then echo >&2 'You need to build test-chmtime:' echo >&2 'Run "make test-chmtime" in the source (toplevel) directory' exit 1 From 07b74a9fc5fe96981c25641366664f188e08d29d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 19 Aug 2010 16:08:11 +0000 Subject: [PATCH 1113/3720] test-lib: Allow overriding of TEST_DIRECTORY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests that test the test-lib.sh itself need to be executed in the dynamically created trash directory, so we can't assume $TEST_DIRECTORY is ../ for those. As a side benefit this change also makes it easy for us to move the t/*.sh tests into subdirectories if we ever want to do that. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- t/test-lib.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 9c089677fb..804f115bf7 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -711,7 +711,13 @@ test_done () { # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. -TEST_DIRECTORY=$(pwd) +if test -z "$TEST_DIRECTORY" +then + # We allow tests to override this, in case they want to run tests + # outside of t/, e.g. for running tests on the test library + # itself. + TEST_DIRECTORY=$(pwd) +fi GIT_BUILD_DIR="$TEST_DIRECTORY"/.. if test -n "$valgrind" From cc17e9f885e3eee9901f7dab5b6bf7a80b315614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 19 Aug 2010 16:08:12 +0000 Subject: [PATCH 1114/3720] t/t0000-basic.sh: Run the passing TODO test inside its own test-lib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the passing TODO test in t0000-basic.sh to run inside its own test-lib.sh. The motivation is to have nothing out of the ordinary on a normal test run for test smoking purposes. If every normal test run has a passing TODO you're more likely to turn a blind eye to it and not to investigate cases where things really are passing unexpectedly. It also makes the prove(1) output less noisy. Before: All tests successful. Test Summary Report ------------------- ./t0000-basic.sh (Wstat: 0 Tests: 46 Failed: 0) TODO passed: 5 Files=484, Tests=6229, 143 wallclock secs ( 4.00 usr 4.15 sys + 104.77 cusr 351.57 csys = 464.49 CPU) Result: PASS And after: All tests successful. Files=484, Tests=6228, 139 wallclock secs ( 4.07 usr 4.25 sys + 104.54 cusr 350.85 csys = 463.71 CPU) Result: PASS Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- t/t0000-basic.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 960208504b..f688bd3ef5 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -54,9 +54,40 @@ test_expect_success 'success is reported like this' ' test_expect_failure 'pretend we have a known breakage' ' false ' + +test_expect_success 'pretend we have fixed a known breakage (run in sub test-lib)' " + mkdir passing-todo && + (cd passing-todo && + cat >passing-todo.sh <out 2>err && + ! test -s err && +cat >expect < Date: Fri, 13 Aug 2010 23:07:33 +0800 Subject: [PATCH 1115/3720] Add tests for line history browser t/t4301-log-line-single-history.sh: test the linear line of history. t/t4302-log-line-merge-history.sh: test the case that there are merges in the history. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- t/t4301-log-line-single-history.sh | 685 +++++++++++++++++++++++++++++ t/t4302-log-line-merge-history.sh | 174 ++++++++ 2 files changed, 859 insertions(+) create mode 100755 t/t4301-log-line-single-history.sh create mode 100755 t/t4302-log-line-merge-history.sh diff --git a/t/t4301-log-line-single-history.sh b/t/t4301-log-line-single-history.sh new file mode 100755 index 0000000000..3197ea8138 --- /dev/null +++ b/t/t4301-log-line-single-history.sh @@ -0,0 +1,685 @@ +#!/bin/sh +# +# Copyright (c) 2010 Bo Yang +# + +test_description='Test git log -L with single line of history' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh + +cat >path0 <<\EOF +void func() +{ + int a = 0; + int b = 1; + int c; + c = a + b; +} +EOF + +cat >path1 <<\EOF +void output() +{ + printf("hello world"); +} +EOF + +test_expect_success 'add path0/path1 and commit.' ' + git add path0 path1 && + git commit -m "Base commit" +' + +cat >path0 <<\EOF +void func() +{ + int a = 10; + int b = 11; + int c; + c = a + b; +} +EOF + +cat >path1 <<\EOF +void output() +{ + const char *str = "hello world!"; + printf("%s", str); +} +EOF + +test_expect_success 'Change the 2,3 lines of path0 and path1.' ' + git add path0 path1 && + git commit -m "Change 2,3 lines of path0 and path1" +' + +cat >path0 <<\EOF +void func() +{ + int a = 10; + int b = 11; + int c; + c = 10 * (a + b); +} +EOF + +test_expect_success 'Change the 5th line of path0.' ' + git add path0 && + git commit -m "Change the 5th line of path0" +' + +cat >path0 <<\EOF +void func() +{ + int a = 10; + int b = 11; + printf("%d", a - b); +} +EOF + +test_expect_success 'Final change of path0.' ' + git add path0 && + git commit -m "Final change of path0" +' + +cat >expected-path0 <<\EOF +Final change of path0 + +diff --git a/path0 b/path0 +index ccdf243..ccf8bcf 100644 +--- a/path0 ++++ b/path0 +@@ -1,7 +1,6 @@ + void func() + { + int a = 10; + int b = 11; +- int c; +- c = 10 * (a + b); ++ printf("%d", a - b); + } + +Change the 5th line of path0 + +diff --git a/path0 b/path0 +index b0eb888..ccdf243 100644 +--- a/path0 ++++ b/path0 +@@ -1,7 +1,7 @@ + void func() + { + int a = 10; + int b = 11; + int c; +- c = a + b; ++ c = 10 * (a + b); + } + +Change 2,3 lines of path0 and path1 + +diff --git a/path0 b/path0 +index fb33939..b0eb888 100644 +--- a/path0 ++++ b/path0 +@@ -1,7 +1,7 @@ + void func() + { +- int a = 0; +- int b = 1; ++ int a = 10; ++ int b = 11; + int c; + c = a + b; + } + +Base commit + +diff --git a/path0 b/path0 +new file mode 100644 +index 0000000..fb33939 +--- /dev/null ++++ b/path0 +@@ -0,0 +1,7 @@ ++void func() ++{ ++ int a = 0; ++ int b = 1; ++ int c; ++ c = a + b; ++} +EOF + +cat >expected-path1 <<\EOF +Change 2,3 lines of path0 and path1 + +diff --git a/path1 b/path1 +index 52be2a5..cc54b12 100644 +--- a/path1 ++++ b/path1 +@@ -1,4 +1,5 @@ + void output() + { +- printf("hello world"); ++ const char *str = "hello world!"; ++ printf("%s", str); + } + +Base commit + +diff --git a/path1 b/path1 +new file mode 100644 +index 0000000..52be2a5 +--- /dev/null ++++ b/path1 +@@ -0,0 +1,4 @@ ++void output() ++{ ++ printf("hello world"); ++} +EOF + +cat >expected-pathall <<\EOF +Final change of path0 + +diff --git a/path0 b/path0 +index ccdf243..ccf8bcf 100644 +--- a/path0 ++++ b/path0 +@@ -1,7 +1,6 @@ + void func() + { + int a = 10; + int b = 11; +- int c; +- c = 10 * (a + b); ++ printf("%d", a - b); + } + +Change the 5th line of path0 + +diff --git a/path0 b/path0 +index b0eb888..ccdf243 100644 +--- a/path0 ++++ b/path0 +@@ -1,7 +1,7 @@ + void func() + { + int a = 10; + int b = 11; + int c; +- c = a + b; ++ c = 10 * (a + b); + } + +Change 2,3 lines of path0 and path1 + +diff --git a/path0 b/path0 +index fb33939..b0eb888 100644 +--- a/path0 ++++ b/path0 +@@ -1,7 +1,7 @@ + void func() + { +- int a = 0; +- int b = 1; ++ int a = 10; ++ int b = 11; + int c; + c = a + b; + } +diff --git a/path1 b/path1 +index 52be2a5..cc54b12 100644 +--- a/path1 ++++ b/path1 +@@ -1,4 +1,5 @@ + void output() + { +- printf("hello world"); ++ const char *str = "hello world!"; ++ printf("%s", str); + } + +Base commit + +diff --git a/path0 b/path0 +new file mode 100644 +index 0000000..fb33939 +--- /dev/null ++++ b/path0 +@@ -0,0 +1,7 @@ ++void func() ++{ ++ int a = 0; ++ int b = 1; ++ int c; ++ c = a + b; ++} +diff --git a/path1 b/path1 +new file mode 100644 +index 0000000..52be2a5 +--- /dev/null ++++ b/path1 +@@ -0,0 +1,4 @@ ++void output() ++{ ++ printf("hello world"); ++} +EOF + +cat >expected-linenum <<\EOF +Change 2,3 lines of path0 and path1 + +diff --git a/path0 b/path0 +index fb33939..b0eb888 100644 +--- a/path0 ++++ b/path0 +@@ -2,3 +2,3 @@ + { +- int a = 0; +- int b = 1; ++ int a = 10; ++ int b = 11; + +Base commit + +diff --git a/path0 b/path0 +new file mode 100644 +index 0000000..fb33939 +--- /dev/null ++++ b/path0 +@@ -0,0 +2,3 @@ ++{ ++ int a = 0; ++ int b = 1; +EOF + +cat >expected-always <<\EOF +Final change of path0 + +diff --git a/path0 b/path0 +index ccdf243..ccf8bcf 100644 +--- a/path0 ++++ b/path0 +@@ -2,3 +2,3 @@ + { + int a = 10; + int b = 11; + +Change the 5th line of path0 + +diff --git a/path0 b/path0 +index b0eb888..ccdf243 100644 +--- a/path0 ++++ b/path0 +@@ -2,3 +2,3 @@ + { + int a = 10; + int b = 11; + +Change 2,3 lines of path0 and path1 + +diff --git a/path0 b/path0 +index fb33939..b0eb888 100644 +--- a/path0 ++++ b/path0 +@@ -2,3 +2,3 @@ + { +- int a = 0; +- int b = 1; ++ int a = 10; ++ int b = 11; + +Base commit + +diff --git a/path0 b/path0 +new file mode 100644 +index 0000000..fb33939 +--- /dev/null ++++ b/path0 +@@ -0,0 +2,3 @@ ++{ ++ int a = 0; ++ int b = 1; +EOF + +test_expect_success 'Show the line level log of path0' ' + git log --pretty=format:%s%n%b -L /func/,/^}/ path0 > current-path0 +' + +test_expect_success 'validate the path0 output.' ' + test_cmp current-path0 expected-path0 +' + +test_expect_success 'Show the line level log of path1' ' + git log --pretty=format:%s%n%b -L /output/,/^}/ path1 > current-path1 +' + +test_expect_success 'validate the path1 output.' ' + test_cmp current-path1 expected-path1 +' + +test_expect_success 'Show the line level log of two files' ' + git log --pretty=format:%s%n%b -L /func/,/^}/ path0 -L /output/,/^}/ path1 > current-pathall +' + +test_expect_success 'validate the all path output.' ' + test_cmp current-pathall expected-pathall +' + +test_expect_success 'Test the line number argument' ' + git log --pretty=format:%s%n%b -L 2,4 path0 > current-linenum +' + +test_expect_success 'validate the line number output.' ' + test_cmp current-linenum expected-linenum +' +test_expect_success 'Test the --full-line-diff option' ' + git log --pretty=format:%s%n%b --full-line-diff -L 2,4 path0 > current-always +' + +test_expect_success 'validate the --full-line-diff output.' ' + test_cmp current-always expected-always +' + +# Rerun all log with graph +test_expect_success 'Show the line level log of path0 with --graph' ' + git log --pretty=format:%s%n%b --graph -L /func/,/^}/ path0 > current-path0-graph +' + +test_expect_success 'Show the line level log of path1 with --graph' ' + git log --pretty=format:%s%n%b --graph -L /output/,/^}/ path1 > current-path1-graph +' + +test_expect_success 'Show the line level log of two files with --graph' ' + git log --pretty=format:%s%n%b --graph -L /func/,/^}/ path0 --graph -L /output/,/^}/ path1 > current-pathall-graph +' + +test_expect_success 'Test the line number argument with --graph' ' + git log --pretty=format:%s%n%b --graph -L 2,4 path0 > current-linenum-graph +' + +test_expect_success 'Test the --full-line-diff option with --graph option' ' + git log --pretty=format:%s%n%b --full-line-diff --graph -L 2,4 path0 > current-always-graph +' + +cat > expected-path0-graph <<\EOF +* Final change of path0 +| +| diff --git a/path0 b/path0 +| index ccdf243..ccf8bcf 100644 +| --- a/path0 +| +++ b/path0 +| @@ -1,7 +1,6 @@ +| void func() +| { +| int a = 10; +| int b = 11; +| - int c; +| - c = 10 * (a + b); +| + printf("%d", a - b); +| } +| +* Change the 5th line of path0 +| +| diff --git a/path0 b/path0 +| index b0eb888..ccdf243 100644 +| --- a/path0 +| +++ b/path0 +| @@ -1,7 +1,7 @@ +| void func() +| { +| int a = 10; +| int b = 11; +| int c; +| - c = a + b; +| + c = 10 * (a + b); +| } +| +* Change 2,3 lines of path0 and path1 +| +| diff --git a/path0 b/path0 +| index fb33939..b0eb888 100644 +| --- a/path0 +| +++ b/path0 +| @@ -1,7 +1,7 @@ +| void func() +| { +| - int a = 0; +| - int b = 1; +| + int a = 10; +| + int b = 11; +| int c; +| c = a + b; +| } +| +* Base commit + + diff --git a/path0 b/path0 + new file mode 100644 + index 0000000..fb33939 + --- /dev/null + +++ b/path0 + @@ -0,0 +1,7 @@ + +void func() + +{ + + int a = 0; + + int b = 1; + + int c; + + c = a + b; + +} +EOF + +cat > expected-path1-graph <<\EOF +* Change 2,3 lines of path0 and path1 +| +| diff --git a/path1 b/path1 +| index 52be2a5..cc54b12 100644 +| --- a/path1 +| +++ b/path1 +| @@ -1,4 +1,5 @@ +| void output() +| { +| - printf("hello world"); +| + const char *str = "hello world!"; +| + printf("%s", str); +| } +| +* Base commit + + diff --git a/path1 b/path1 + new file mode 100644 + index 0000000..52be2a5 + --- /dev/null + +++ b/path1 + @@ -0,0 +1,4 @@ + +void output() + +{ + + printf("hello world"); + +} +EOF + +cat > expected-pathall-graph <<\EOF +* Final change of path0 +| +| diff --git a/path0 b/path0 +| index ccdf243..ccf8bcf 100644 +| --- a/path0 +| +++ b/path0 +| @@ -1,7 +1,6 @@ +| void func() +| { +| int a = 10; +| int b = 11; +| - int c; +| - c = 10 * (a + b); +| + printf("%d", a - b); +| } +| +* Change the 5th line of path0 +| +| diff --git a/path0 b/path0 +| index b0eb888..ccdf243 100644 +| --- a/path0 +| +++ b/path0 +| @@ -1,7 +1,7 @@ +| void func() +| { +| int a = 10; +| int b = 11; +| int c; +| - c = a + b; +| + c = 10 * (a + b); +| } +| +* Change 2,3 lines of path0 and path1 +| +| diff --git a/path0 b/path0 +| index fb33939..b0eb888 100644 +| --- a/path0 +| +++ b/path0 +| @@ -1,7 +1,7 @@ +| void func() +| { +| - int a = 0; +| - int b = 1; +| + int a = 10; +| + int b = 11; +| int c; +| c = a + b; +| } +| diff --git a/path1 b/path1 +| index 52be2a5..cc54b12 100644 +| --- a/path1 +| +++ b/path1 +| @@ -1,4 +1,5 @@ +| void output() +| { +| - printf("hello world"); +| + const char *str = "hello world!"; +| + printf("%s", str); +| } +| +* Base commit + + diff --git a/path0 b/path0 + new file mode 100644 + index 0000000..fb33939 + --- /dev/null + +++ b/path0 + @@ -0,0 +1,7 @@ + +void func() + +{ + + int a = 0; + + int b = 1; + + int c; + + c = a + b; + +} + diff --git a/path1 b/path1 + new file mode 100644 + index 0000000..52be2a5 + --- /dev/null + +++ b/path1 + @@ -0,0 +1,4 @@ + +void output() + +{ + + printf("hello world"); + +} +EOF + +cat > expected-linenum-graph <<\EOF +* Change 2,3 lines of path0 and path1 +| +| diff --git a/path0 b/path0 +| index fb33939..b0eb888 100644 +| --- a/path0 +| +++ b/path0 +| @@ -2,3 +2,3 @@ +| { +| - int a = 0; +| - int b = 1; +| + int a = 10; +| + int b = 11; +| +* Base commit + + diff --git a/path0 b/path0 + new file mode 100644 + index 0000000..fb33939 + --- /dev/null + +++ b/path0 + @@ -0,0 +2,3 @@ + +{ + + int a = 0; + + int b = 1; +EOF + +cat > expected-always-graph <<\EOF +* Final change of path0 +| +| diff --git a/path0 b/path0 +| index ccdf243..ccf8bcf 100644 +| --- a/path0 +| +++ b/path0 +| @@ -2,3 +2,3 @@ +| { +| int a = 10; +| int b = 11; +| +* Change the 5th line of path0 +| +| diff --git a/path0 b/path0 +| index b0eb888..ccdf243 100644 +| --- a/path0 +| +++ b/path0 +| @@ -2,3 +2,3 @@ +| { +| int a = 10; +| int b = 11; +| +* Change 2,3 lines of path0 and path1 +| +| diff --git a/path0 b/path0 +| index fb33939..b0eb888 100644 +| --- a/path0 +| +++ b/path0 +| @@ -2,3 +2,3 @@ +| { +| - int a = 0; +| - int b = 1; +| + int a = 10; +| + int b = 11; +| +* Base commit + + diff --git a/path0 b/path0 + new file mode 100644 + index 0000000..fb33939 + --- /dev/null + +++ b/path0 + @@ -0,0 +2,3 @@ + +{ + + int a = 0; + + int b = 1; +EOF + +test_expect_success 'validate the path0 output.' ' + test_cmp current-path0-graph expected-path0-graph +' + +test_expect_success 'validate the path1 output.' ' + test_cmp current-path1-graph expected-path1-graph +' + +test_expect_success 'validate the all path output.' ' + test_cmp current-pathall-graph expected-pathall-graph +' + +test_expect_success 'validate graph output' ' + test_cmp current-linenum-graph expected-linenum-graph +' + +test_expect_success 'validate --full-line-diff output' ' + test_cmp current-always-graph expected-always-graph +' + +test_done diff --git a/t/t4302-log-line-merge-history.sh b/t/t4302-log-line-merge-history.sh new file mode 100755 index 0000000000..86341163e2 --- /dev/null +++ b/t/t4302-log-line-merge-history.sh @@ -0,0 +1,174 @@ +#!/bin/sh +# +# Copyright (c) 2010 Bo Yang +# + +test_description='Test git log -L with merge commit' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh + +cat >path0 <<\EOF +void func() +{ + printf("hello"); +} +EOF + +test_expect_success 'Add path0 and commit.' ' + git add path0 && + git commit -m "Base commit" +' + +cat >path0 <<\EOF +void func() +{ + printf("hello earth"); +} +EOF + +test_expect_success 'Change path0 in master.' ' + git add path0 && + git commit -m "Change path0 in master" +' + +test_expect_success 'Make a new branch from the base commit' ' + git checkout -b feature master^ +' + +cat >path0 <<\EOF +void func() +{ + print("hello moon"); +} +EOF + +test_expect_success 'Change path0 in feature.' ' + git add path0 && + git commit -m "Change path0 in feature" +' + +test_expect_success 'Merge the master to feature' ' + ! git merge master +' + +cat >path0 <<\EOF +void func() +{ + printf("hello earth and moon"); +} +EOF + +test_expect_success 'Resolve the conflict' ' + git add path0 && + git commit -m "Merge two branches" +' + +test_expect_success 'Show the line level log of path0' ' + git log --pretty=format:%s%n%b -L /func/,/^}/ path0 > current +' + +cat >expected <<\EOF +Merge two branches + +nontrivial merge found +path0 +@@ 3,1 @@ + printf("hello earth and moon"); + + +Change path0 in master + +diff --git a/path0 b/path0 +index 56aeee5..11e66c5 100644 +--- a/path0 ++++ b/path0 +@@ -1,4 +1,4 @@ + void func() + { +- printf("hello"); ++ printf("hello earth"); + } + +Change path0 in feature + +diff --git a/path0 b/path0 +index 56aeee5..258fced 100644 +--- a/path0 ++++ b/path0 +@@ -1,4 +1,4 @@ + void func() + { +- printf("hello"); ++ print("hello moon"); + } + +Base commit + +diff --git a/path0 b/path0 +new file mode 100644 +index 0000000..56aeee5 +--- /dev/null ++++ b/path0 +@@ -0,0 +1,4 @@ ++void func() ++{ ++ printf("hello"); ++} +EOF + +cat > expected-graph <<\EOF +* Merge two branches +|\ +| | +| | nontrivial merge found +| | path0 +| | @@ 3,1 @@ +| | printf("hello earth and moon"); +| | +| | +| * Change path0 in master +| | +| | diff --git a/path0 b/path0 +| | index 56aeee5..11e66c5 100644 +| | --- a/path0 +| | +++ b/path0 +| | @@ -3,1 +3,1 @@ +| | - printf("hello"); +| | + printf("hello earth"); +| | +* | Change path0 in feature +|/ +| +| diff --git a/path0 b/path0 +| index 56aeee5..258fced 100644 +| --- a/path0 +| +++ b/path0 +| @@ -3,1 +3,1 @@ +| - printf("hello"); +| + print("hello moon"); +| +* Base commit + + diff --git a/path0 b/path0 + new file mode 100644 + index 0000000..56aeee5 + --- /dev/null + +++ b/path0 + @@ -0,0 +3,1 @@ + + printf("hello"); +EOF + +test_expect_success 'Show the line log of the 2 line of path0 with graph' ' + git log --pretty=format:%s%n%b --graph -L 3,+1 path0 > current-graph +' + +test_expect_success 'validate the output.' ' + test_cmp current expected +' + +test_expect_success 'validate the graph output.' ' + test_cmp current-graph expected-graph +' + +test_done From 6eed493d2dafda28dfeb237ca91d431e48c0d05c Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 11 Aug 2010 23:03:42 +0800 Subject: [PATCH 1116/3720] Document line history browser Both 'git log' and 'git blame' support the same format of '-L' arguments, so we refactor its description into a new file. And it is possible to use more than one '-L' option for each path. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- Documentation/blame-options.txt | 19 +------------------ Documentation/git-log.txt | 15 +++++++++++++++ Documentation/line-range-format.txt | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 Documentation/line-range-format.txt diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index 16e3c68576..3526835d35 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -13,24 +13,7 @@ Annotate only the given line range. and can take one of these forms: - - number -+ -If or is a number, it specifies an -absolute line number (lines count from 1). -+ - -- /regex/ -+ -This form will use the first line matching the given -POSIX regex. If is a regex, it will search -starting at the line given by . -+ - -- +offset or -offset -+ -This is only valid for and will specify a number -of lines before or after the line given by . -+ +include::line-range-format.txt[] -l:: Show long rev (Default: off). diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index e970664fe1..6f712e7840 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -9,6 +9,7 @@ git-log - Show commit logs SYNOPSIS -------- 'git log' [] [..] [[\--] ...] +'git log' [] -L n,m DESCRIPTION ----------- @@ -19,6 +20,9 @@ command to control what is shown and how, and options applicable to the 'git diff-*' commands to control how the changes each commit introduces are shown. +With '-L' option, the command will help to trace the history of user specified +line ranges. It can trace multiple ranges coming from multiple files. + OPTIONS ------- @@ -63,6 +67,17 @@ OPTIONS Note that only message is considered, if also a diff is shown its size is not included. +-L ,:: + The line range. and can take one of these forms: + +include::line-range-format.txt[] +You can also specify this option more than once before each path. + + +--full-line-diff:: + Always print the interesting range even if the current commit + does not change any line of the range. + [\--] ...:: Show only commits that affect any of the specified paths. To prevent confusion with options and branch names, paths may need diff --git a/Documentation/line-range-format.txt b/Documentation/line-range-format.txt new file mode 100644 index 0000000000..265bc23290 --- /dev/null +++ b/Documentation/line-range-format.txt @@ -0,0 +1,18 @@ +- number ++ +If or is a number, it specifies an +absolute line number (lines count from 1). ++ + +- /regex/ ++ +This form will use the first line matching the given +POSIX regex. If is a regex, it will search +starting at the line given by . ++ + +- +offset or -offset ++ +This is only valid for and will specify a number +of lines before or after the line given by . ++ From 477e5a805ef9551634ed9cd85776680510a50fb3 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Tue, 24 Aug 2010 02:34:10 -0500 Subject: [PATCH 1117/3720] tests: simplify "missing PREREQ" message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a test has no prerequisites satisfied (the usual case), instead of "missing THING of THING", just say "missing THING". This does not affect the output when a test is skipped due to a missing prerequisites if another prerequisite is satisfied. For example: instead of ok 8 # skip notes work (missing EXPENSIVE of EXPENSIVE) ok 9 # skip notes timing with /usr/bin/time (missing EXPENSIVE of USR_BIN_TIME,EXPENSIVE) write ok 8 # skip notes work (missing EXPENSIVE) ok 9 # skip notes timing with /usr/bin/time (missing EXPENSIVE of USR_BIN_TIME,EXPENSIVE) Cc: Ævar Arnfjörð Bjarmason Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- t/test-lib.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 804f115bf7..c67a9c6e6d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -418,8 +418,14 @@ test_skip () { fi case "$to_skip" in t) + of_prereq= + if test "$missing_prereq" != "$prereq" + then + of_prereq=" of $prereq" + fi + say_color skip >&3 "skipping test: $@" - say_color skip "ok $test_count # skip $1 (missing $missing_prereq of $prereq)" + say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})" : true ;; *) From 2f34416b60afa83a26f0e06211e3675076dd4eca Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 25 Aug 2010 12:18:40 +0200 Subject: [PATCH 1118/3720] checkout: respect diff.ignoreSubmodules setting When 'git checkout' reports uncommitted changes, it also does so for submodules. The default mode is now to look really hard into submodules, not only for different commits, but also for modified files. Since this can be pretty expensive when there are a lot (and large) submodules, there is the diff.ignoreSubmodules option. Let's respect that setting when 'git checkout' reports the uncommitted changes, since it does nothing else than a 'git diff --name-status'. Signed-off-by: Johannes Schindelin --- builtin/checkout.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/builtin/checkout.c b/builtin/checkout.c index 1994be92c6..e73bfe3403 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -18,6 +18,7 @@ #include "xdiff-interface.h" #include "ll-merge.h" #include "resolve-undo.h" +#include "submodule.h" static const char * const checkout_usage[] = { "git checkout [options] ", @@ -36,6 +37,7 @@ struct checkout_opts { const char *new_orphan_branch; int new_branch_log; enum branch_track track; + struct diff_options diff_options; }; static int post_checkout_hook(struct commit *old, struct commit *new, @@ -274,12 +276,13 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, return errs; } -static void show_local_changes(struct object *head) +static void show_local_changes(struct object *head, struct diff_options *opts) { struct rev_info rev; /* I think we want full paths, even if we're in a subdirectory. */ init_revisions(&rev, NULL); rev.abbrev = 0; + rev.diffopt.flags = opts->flags; rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS; if (diff_setup_done(&rev.diffopt) < 0) die("diff_setup_done failed"); @@ -456,7 +459,7 @@ static int merge_working_tree(struct checkout_opts *opts, die("unable to write new index file"); if (!opts->force && !opts->quiet) - show_local_changes(&new->commit->object); + show_local_changes(&new->commit->object, &opts->diff_options); return 0; } @@ -600,7 +603,12 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) static int git_checkout_config(const char *var, const char *value, void *cb) { - return git_xmerge_config(var, value, cb); + if (!strcmp(var, "diff.ignoresubmodules")) { + struct checkout_opts *opts = cb; + handle_ignore_submodules_arg(&opts->diff_options, value); + return 0; + } + return git_xmerge_config(var, value, NULL); } static int interactive_checkout(const char *revision, const char **pathspec, @@ -681,7 +689,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); - git_config(git_checkout_config, NULL); + git_config(git_checkout_config, &opts); opts.track = BRANCH_TRACK_UNSPECIFIED; From 5ac131bc104cc1c74696de5643de4b97631e1202 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 1119/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 8b7c243473..d2d4ad3f37 100644 --- a/Makefile +++ b/Makefile @@ -1954,6 +1954,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1961,6 +1962,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 92615c5126e5441c06575769946a083bcb38fbe2 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 1120/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 14cbfadd3b239f1e369459263b6ba6fa43df3855 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1121/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From f25eee3ff2bf7a435ca24cde6cf8f61a6e6ba2c6 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1122/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 0510ac795c..ee60031aa4 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index be02a422d1..d9726930e6 100644 --- a/cache.h +++ b/cache.h @@ -551,6 +551,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f2d9e1fd97..9f6df8762d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index cdcf5836c6..42e94f991b 100644 --- a/config.c +++ b/config.c @@ -595,6 +595,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index eeb26876a1..34ec3ac023 100644 --- a/environment.c +++ b/environment.c @@ -54,6 +54,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 877096ecb0..dae7686fc2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -510,4 +510,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 60e342888099a3ffd4776bfd23967fa908caf09e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1123/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 9f6df8762d..884f698873 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From b0f2bc2a967bcbeef048e52dd3253b2dc3f56269 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1124/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From cc6d315f3a912985887b51fdad45d7327b9a2af4 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 1125/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..1eaa83f686 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NONMINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NONMINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/test-lib.sh b/t/test-lib.sh index 9263614017..920259881f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -939,6 +939,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From dfcf247fdb1c377726a46751b969184f26c498a8 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1126/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index bb104895a9..76981e563d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1213,9 +1213,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2015,7 +2012,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2027,12 +2024,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2053,18 +2057,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2085,20 +2086,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 56e74ba1603113576bb4240de0c9b9710dab7dd9 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1127/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 884f698873..208b9f987e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 1848523948a27195e829c834d06b08e833df27de Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1128/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 208b9f987e..14be1bbb2e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1248,7 +1264,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From c7146caf30630b44e3cddf3a6492fa74bdc03882 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1129/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 14be1bbb2e..d813203ea0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1305,6 +1358,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From c6a119e59d370154d8ee702c858d44adec89eee2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1130/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d813203ea0..ef23b6274e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 7e31192e6092496d6db8f68cb2e03c0df6fcb8c2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1131/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 76981e563d..ccbed506ad 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 4c9190d5aadbc09efbf91518cbf068c00691d6cf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1132/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From a01d212a07255abca1ed0fb3fb2b78df5be8bf03 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1133/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ef23b6274e..d770c2d00c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 8850b9a8330e5d97974c76b34e74f568869608a6 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1134/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d770c2d00c..12f230b665 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1590,6 +1590,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1599,9 +1600,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 0b944a49e7198866ce7346f928bdf55c9c669411 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1135/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7a7599987a..4c0ce3138a 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -324,4 +324,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 920259881f..1349a989ee 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -934,6 +934,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From cf55828c0fa9044ac1f72bb69973577d326896d0 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1136/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 12f230b665..0c67afd55e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From ec16039da9b48f485b29fffc063d1b035ec49a25 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 1137/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0c67afd55e..2718b7d649 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 33dae2896370ef8526ebb6cec2145cbd1836ac39 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 1138/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..6b9f76a27d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 48bba6d5dc0925bcaa7a10e0b67acb72f22fce8e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1139/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 18b07d9d36..0182d168ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 9348921d8ce98df2057a0188e245f9de0880ef8f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1140/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index ee60031aa4..4e97449e74 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1596,6 +1596,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 09fd27c37e1cac582f8f40cce8e83dd7a5debcce Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1141/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2718b7d649..62e7ba11ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 0e7d8bbb3579e41ca64038e32fd59cea1274af83 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1142/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 6dab3bf6a7..53f89d6cd2 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1017,7 +1017,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From aae8856c966383a7118553c939c53942d5fabde7 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1143/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 53f89d6cd2..e157e4b469 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1103,7 +1103,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 3060d1601012050281f0f23ce7eaf8e0381f0eba Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1144/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 62e7ba11ce..ec26ba6655 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 4bd6edbf6ded115afb71b17c0654f64e17d5dfa1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1145/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index ec26ba6655..c058b22654 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1731,3 +1731,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 42e94f991b..1d2410e512 100644 --- a/config.c +++ b/config.c @@ -804,7 +804,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index dae7686fc2..1e4038d61f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -514,4 +514,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index a2c9d1e24a..30d66a94c0 100644 --- a/path.c +++ b/path.c @@ -353,7 +353,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 0ede5f550366208e9cfc653be49c534b9a612e4a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1146/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 1349a989ee..fb8fbd8d70 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -837,6 +837,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . ../GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From de787e4ac889b42dc7a28bd80cb2190ca6189a9f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1147/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 4601c425403ceaa512aeb8fc3d13802aebc3e7dd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1148/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From d2a5ef055a97e71b3b213798ba797292fa038210 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1149/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6b9f76a27d..ae9fc2346d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From e72c5a6239444017dc39cbdabfecfca90f309a6e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1150/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index fb8fbd8d70..9d6697b1a2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From de2ba333c02f1dd128a548f0802c58da834481f4 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1151/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From 2c28d74dceaab920167e426715cbd919a09a9701 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1152/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index d9726930e6..ec0d3fc317 100644 --- a/cache.h +++ b/cache.h @@ -720,7 +720,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index c058b22654..4dc751d047 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1749,3 +1749,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 1e4038d61f..cc469b2053 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -179,6 +179,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 30d66a94c0..0e560cabac 100644 --- a/path.c +++ b/path.c @@ -768,10 +768,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From e4d5143840c97c38912d8254406ff58a70b1a4e5 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1153/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 13a2cf3c2576a1d5e37e9a9daa4b026a00b502c8 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1154/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4dc751d047..f96d8367b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1752,23 +1752,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 9439967d264668bc9c0cd27ec3e5d25bdaeae146 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 17:40:44 +0200 Subject: [PATCH 1155/3720] Make sure that git_getpass() never returns NULL The result of git_getpass() is used without checking for NULL, so let's just die() instead of returning NULL. Signed-off-by: Johannes Schindelin --- connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 02e738a014..d3e967fcd9 100644 --- a/connect.c +++ b/connect.c @@ -628,8 +628,12 @@ char *git_getpass(const char *prompt) askpass = getenv("GIT_ASKPASS"); - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; From 4956135fd0fccc87ba1cb00a3f9181a80dea63b2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1156/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ccbed506ad..8eeebe06e2 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 57916d5259dd3d5df7e82a54d257261b4fe29c1e Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1157/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 69035b8f15888a14068d0727b56a9040620768b0 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1158/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f96d8367b2..b0ad9192fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -701,11 +701,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 4ba1bb0b54561dbdba98a117a46db5160afd67d3 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1159/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From eb728ee718cf60198be8ae17d14432c0c676c1cf Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1160/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From e9be28f0e4fbacaab541bfa802e6b592b5b6e766 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1161/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From eed7a67bbb4ad53f54dc32ac8d26cf30c853f5dd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1162/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From f3638bd500f016fb9d6fed44539e1cea634d379c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Aug 2010 12:04:40 +0200 Subject: [PATCH 1163/3720] Fix typo in pack-objects' usage Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0e81673118..3756cf36ee 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -30,7 +30,7 @@ static const char pack_usage[] = " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n" " [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n" " [--reflog] [--stdout | base-name] [--include-tag]\n" - " [--keep-unreachable | --unpack-unreachable \n" + " [--keep-unreachable | --unpack-unreachable]\n" " [ Date: Wed, 25 Aug 2010 12:18:40 +0200 Subject: [PATCH 1164/3720] checkout: respect diff.ignoreSubmodules setting When 'git checkout' reports uncommitted changes, it also does so for submodules. The default mode is now to look really hard into submodules, not only for different commits, but also for modified files. Since this can be pretty expensive when there are a lot (and large) submodules, there is the diff.ignoreSubmodules option. Let's respect that setting when 'git checkout' reports the uncommitted changes, since it does nothing else than a 'git diff --name-status'. Signed-off-by: Johannes Schindelin --- builtin/checkout.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/builtin/checkout.c b/builtin/checkout.c index ff5ac1e0ff..19c23b26e0 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -18,6 +18,7 @@ #include "xdiff-interface.h" #include "ll-merge.h" #include "resolve-undo.h" +#include "submodule.h" static const char * const checkout_usage[] = { "git checkout [options] ", @@ -40,6 +41,7 @@ struct checkout_opts { const char *new_orphan_branch; int new_branch_log; enum branch_track track; + struct diff_options diff_options; }; static int post_checkout_hook(struct commit *old, struct commit *new, @@ -282,11 +284,12 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, return errs; } -static void show_local_changes(struct object *head) +static void show_local_changes(struct object *head, struct diff_options *opts) { struct rev_info rev; /* I think we want full paths, even if we're in a subdirectory. */ init_revisions(&rev, NULL); + rev.diffopt.flags = opts->flags; rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS; if (diff_setup_done(&rev.diffopt) < 0) die("diff_setup_done failed"); @@ -471,7 +474,7 @@ static int merge_working_tree(struct checkout_opts *opts, die("unable to write new index file"); if (!opts->force && !opts->quiet) - show_local_changes(&new->commit->object); + show_local_changes(&new->commit->object, &opts->diff_options); return 0; } @@ -619,7 +622,12 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) static int git_checkout_config(const char *var, const char *value, void *cb) { - return git_xmerge_config(var, value, cb); + if (!strcmp(var, "diff.ignoresubmodules")) { + struct checkout_opts *opts = cb; + handle_ignore_submodules_arg(&opts->diff_options, value); + return 0; + } + return git_xmerge_config(var, value, NULL); } static int interactive_checkout(const char *revision, const char **pathspec, @@ -703,7 +711,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); - git_config(git_checkout_config, NULL); + git_config(git_checkout_config, &opts); opts.track = BRANCH_TRACK_UNSPECIFIED; From 4598af09609062539212ee36913c25c3553125c4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 26 Aug 2010 14:34:07 +0200 Subject: [PATCH 1165/3720] Fix compile error on MinGW Signed-off-by: Johannes Schindelin --- compat/regex/regexec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index b49585af76..aef8efc292 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -353,7 +353,7 @@ re_search_2 (struct re_pattern_buffer *bufp, weak_alias (__re_search_2, re_search_2) #endif -static int +static int internal_function re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, @@ -397,7 +397,7 @@ re_search_2_stub (struct re_pattern_buffer *bufp, If RET_LEN is nonzero the length of the match is returned (re_match style); otherwise the position of the match is returned. */ -static int +static int internal_function re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, @@ -484,7 +484,7 @@ re_search_stub (struct re_pattern_buffer *bufp, return rval; } -static unsigned +static unsigned internal_function re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs, int regs_allocated) @@ -614,7 +614,7 @@ re_exec (s) Note: We assume front end functions already check ranges. (START + RANGE >= 0 && START + RANGE <= LENGTH) */ -static reg_errcode_t +static reg_errcode_t internal_function re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, @@ -938,7 +938,7 @@ re_search_internal (const regex_t *preg, return err; } -static reg_errcode_t +static reg_errcode_t internal_function prune_impossible_nodes (re_match_context_t *mctx) { const re_dfa_t *const dfa = mctx->dfa; From 9b178ba84defc24e32168f903ee47f99a355f004 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sun, 29 Aug 2010 17:13:15 +0200 Subject: [PATCH 1166/3720] daemon: add helper function setup_named_sock() Add setup_named_sock() as helper function for socksetup to make it easier to create more than one listen sockets. named_sock_setup can be called more than one time and add the new sockets to the supplied socklist_p. Signed-off-by: Alexander Sulfrian Signed-off-by: Junio C Hamano --- daemon.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/daemon.c b/daemon.c index e22a2b7fa5..deda4cf0a2 100644 --- a/daemon.c +++ b/daemon.c @@ -736,9 +736,9 @@ static int set_reuse_addr(int sockfd) #ifndef NO_IPV6 -static int socksetup(char *listen_addr, int listen_port, int **socklist_p) +static int setup_named_sock(char *listen_addr, int listen_port, int **socklist_p, int socknum) { - int socknum = 0, *socklist = NULL; + int *socklist = *socklist_p; int maxfd = -1; char pbuf[NI_MAXSERV]; struct addrinfo hints, *ai0, *ai; @@ -810,8 +810,9 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p) #else /* NO_IPV6 */ -static int socksetup(char *listen_addr, int listen_port, int **socklist_p) +static int setup_named_sock(char *listen_addr, int listen_port, int **socklist_p, int socknum) { + int *socklist = *socklist_p; struct sockaddr_in sin; int sockfd; long flags; @@ -823,41 +824,53 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p) if (listen_addr) { /* Well, host better be an IP address here. */ if (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0) - return 0; + return socknum; } else { sin.sin_addr.s_addr = htonl(INADDR_ANY); } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) - return 0; + return socknum; if (set_reuse_addr(sockfd)) { close(sockfd); - return 0; + return socknum; } if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) { close(sockfd); - return 0; + return socknum; } if (listen(sockfd, 5) < 0) { close(sockfd); - return 0; + return socknum; } flags = fcntl(sockfd, F_GETFD, 0); if (flags >= 0) fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); - *socklist_p = xmalloc(sizeof(int)); - **socklist_p = sockfd; - return 1; + socklist = xrealloc(socklist, sizeof(int) * (socknum + 1)); + socklist[socknum++] = sockfd; + + *socklist_p = socklist; + return socknum; } #endif +static int socksetup(char *listen_addr, int listen_port, int **socklist_p) +{ + int socknum = 0, *socklist = NULL; + + socknum = setup_named_sock(listen_addr, listen_port, &socklist, socknum); + + *socklist_p = socklist; + return socknum; +} + static int service_loop(int socknum, int *socklist) { struct pollfd *pfd; From 1656b65a8b2aea2a072853b9e835ef98c1a6942d Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sun, 29 Aug 2010 17:13:16 +0200 Subject: [PATCH 1167/3720] daemon: allow more than one host address given via --listen When the host has more than one interfaces, daemon can listen to all of them by not giving any --listen option, or listen to only one. Teach it to accept more than one --listen options. Remove the hostname information form the die, if no socket could be created. It would only trigger when no interface out of either all interface or the ones specified on the command line with --listen options, can be listened to and so the user does know which "host" was asked. Signed-off-by: Alexander Sulfrian Signed-off-by: Junio C Hamano --- Documentation/git-daemon.txt | 1 + daemon.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt index 01c9f8eb9e..685aa58cec 100644 --- a/Documentation/git-daemon.txt +++ b/Documentation/git-daemon.txt @@ -85,6 +85,7 @@ OPTIONS be either an IPv4 address or an IPv6 address if supported. If IPv6 is not supported, then --listen=hostname is also not supported and --listen must be given an IPv4 address. + Can be given more than once. Incompatible with '--inetd' option. --port=n:: diff --git a/daemon.c b/daemon.c index deda4cf0a2..bd7574e8dc 100644 --- a/daemon.c +++ b/daemon.c @@ -3,6 +3,7 @@ #include "exec_cmd.h" #include "run-command.h" #include "strbuf.h" +#include "string-list.h" #include @@ -861,11 +862,20 @@ static int setup_named_sock(char *listen_addr, int listen_port, int **socklist_p #endif -static int socksetup(char *listen_addr, int listen_port, int **socklist_p) +static int socksetup(struct string_list *listen_addr, int listen_port, int **socklist_p) { int socknum = 0, *socklist = NULL; - socknum = setup_named_sock(listen_addr, listen_port, &socklist, socknum); + if (!listen_addr->nr) + socknum = setup_named_sock(NULL, listen_port, &socklist, + socknum); + else { + int i; + for (i = 0; i < listen_addr->nr; i++) + socknum = setup_named_sock(listen_addr->items[i].string, + listen_port, &socklist, + socknum); + } *socklist_p = socklist; return socknum; @@ -959,14 +969,14 @@ static void store_pid(const char *path) die_errno("failed to write pid file '%s'", path); } -static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid) +static int serve(struct string_list *listen_addr, int listen_port, struct passwd *pass, gid_t gid) { int socknum, *socklist; socknum = socksetup(listen_addr, listen_port, &socklist); if (socknum == 0) - die("unable to allocate any listen sockets on host %s port %u", - listen_addr, listen_port); + die("unable to allocate any listen sockets on port %u", + listen_port); if (pass && gid && (initgroups(pass->pw_name, gid) || setgid (gid) || @@ -979,7 +989,7 @@ static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t int main(int argc, char **argv) { int listen_port = 0; - char *listen_addr = NULL; + struct string_list listen_addr = STRING_LIST_INIT_NODUP; int inetd_mode = 0; const char *pid_file = NULL, *user_name = NULL, *group_name = NULL; int detach = 0; @@ -987,6 +997,7 @@ int main(int argc, char **argv) struct group *group; gid_t gid = 0; int i; + int return_value; git_extract_argv0_path(argv[0]); @@ -994,7 +1005,7 @@ int main(int argc, char **argv) char *arg = argv[i]; if (!prefixcmp(arg, "--listen=")) { - listen_addr = xstrdup_tolower(arg + 9); + string_list_append(&listen_addr, xstrdup_tolower(arg + 9)); continue; } if (!prefixcmp(arg, "--port=")) { @@ -1119,7 +1130,7 @@ int main(int argc, char **argv) if (inetd_mode && (group_name || user_name)) die("--user and --group are incompatible with --inetd"); - if (inetd_mode && (listen_port || listen_addr)) + if (inetd_mode && (listen_port || (listen_addr.nr > 0))) die("--listen= and --port= are incompatible with --inetd"); else if (listen_port == 0) listen_port = DEFAULT_GIT_PORT; @@ -1174,5 +1185,9 @@ int main(int argc, char **argv) if (pid_file) store_pid(pid_file); - return serve(listen_addr, listen_port, pass, gid); + return_value = serve(&listen_addr, listen_port, pass, gid); + + string_list_clear(&listen_addr, 0); + + return return_value; } From 8f6d1e2796a7f063428017b9a0467b1ee5002d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Mon, 30 Aug 2010 12:00:42 +0000 Subject: [PATCH 1168/3720] test-lib: use subshell instead of cd $new && .. && cd $old MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the test_create_repo code added in v1.2.2~6 to use a subshell instead of keeping track of the old working directory and cd-ing back when it's done. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- t/test-lib.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index c67a9c6e6d..ee3d073791 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -651,14 +651,14 @@ test_when_finished () { test_create_repo () { test "$#" = 1 || error "bug in the test script: not 1 parameter to test-create-repo" - owd=`pwd` repo="$1" mkdir -p "$repo" - cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || - error "cannot run git init -- have you built things yet?" - mv .git/hooks .git/hooks-disabled - cd "$owd" + ( + cd "$repo" || error "Cannot setup test environment" + "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || + error "cannot run git init -- have you built things yet?" + mv .git/hooks .git/hooks-disabled + ) || exit } test_done () { From c9bb83f2411e2e6ac0f417ef839f27fcc4991ddd Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Mon, 30 Aug 2010 11:50:42 +0200 Subject: [PATCH 1169/3720] tests: factor HOME=$(pwd) in test-lib.sh The same pattern is used in many tests, and makes it easy for new ones to rely on $HOME being a trashable, clean, directory. Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano --- t/lib-cvs.sh | 3 --- t/t0001-init.sh | 6 ------ t/t5601-clone.sh | 2 -- t/t9130-git-svn-authors-file.sh | 2 -- t/test-lib.sh | 3 +++ 5 files changed, 3 insertions(+), 13 deletions(-) diff --git a/t/lib-cvs.sh b/t/lib-cvs.sh index b51d2e13a6..44263ade25 100644 --- a/t/lib-cvs.sh +++ b/t/lib-cvs.sh @@ -3,9 +3,6 @@ . ./test-lib.sh unset CVS_SERVER -# for clean cvsps cache -HOME=$(pwd) -export HOME if ! type cvs >/dev/null 2>&1 then diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7a7599987a..7fe8883ae0 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -171,8 +171,6 @@ test_expect_success 'init with init.templatedir set' ' mkdir templatedir-source && echo Content >templatedir-source/file && ( - HOME="`pwd`" && - export HOME && test_config="${HOME}/.gitconfig" && git config -f "$test_config" init.templatedir "${HOME}/templatedir-source" && mkdir templatedir-set && @@ -188,8 +186,6 @@ test_expect_success 'init with init.templatedir set' ' test_expect_success 'init --bare/--shared overrides system/global config' ' ( - HOME="`pwd`" && - export HOME && test_config="$HOME"/.gitconfig && unset GIT_CONFIG_NOGLOBAL && git config -f "$test_config" core.bare false && @@ -205,8 +201,6 @@ test_expect_success 'init --bare/--shared overrides system/global config' ' test_expect_success 'init honors global core.sharedRepository' ' ( - HOME="`pwd`" && - export HOME && test_config="$HOME"/.gitconfig && unset GIT_CONFIG_NOGLOBAL && git config -f "$test_config" core.sharedRepository 0666 && diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 8abb71afcd..8617965ec0 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -163,8 +163,6 @@ test_expect_success 'clone a void' ' test_expect_success 'clone respects global branch.autosetuprebase' ' ( - HOME=$(pwd) && - export HOME && test_config="$HOME/.gitconfig" && unset GIT_CONFIG_NOGLOBAL && git config -f "$test_config" branch.autosetuprebase remote && diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh index 134411e0a5..d5ee39ae9e 100755 --- a/t/t9130-git-svn-authors-file.sh +++ b/t/t9130-git-svn-authors-file.sh @@ -95,8 +95,6 @@ test_expect_success 'fresh clone with svn.authors-file in config' ' ( rm -r "$GIT_DIR" && test x = x"$(git config svn.authorsfile)" && - HOME="`pwd`" && - export HOME && test_config="$HOME"/.gitconfig && unset GIT_CONFIG_NOGLOBAL && unset GIT_DIR && diff --git a/t/test-lib.sh b/t/test-lib.sh index ee3d073791..3073091b9b 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -866,6 +866,9 @@ test_create_repo "$test" # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$test" || exit 1 +HOME=$(pwd) +export HOME + this_test=${0##*/} this_test=${this_test%%-*} for skp in $GIT_SKIP_TESTS From 89cfc85dbcff5ec985dafa7d5b3bf8ce67d9cbf7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 31 Aug 2010 12:44:10 -0700 Subject: [PATCH 1170/3720] Revert ab/i18n out of 'next' It will take a bit more for the topic to mature; better to cook it a bit longer in the 'pu' branch. Signed-off-by: Junio C Hamano --- .gitignore | 2 - INSTALL | 12 --- Makefile | 69 +---------------- config.mak.in | 2 - configure.ac | 12 --- daemon.c | 3 - fast-import.c | 3 - gettext.c | 21 ------ gettext.h | 18 ----- git-sh-i18n.sh | 71 ----------------- git.c | 3 - http-backend.c | 3 - http-fetch.c | 3 - http-push.c | 3 - imap-send.c | 3 - perl/Git/I18N.pm | 91 ---------------------- perl/Makefile | 3 +- perl/Makefile.PL | 14 +--- po/.gitignore | 1 - po/is.po | 47 ------------ shell.c | 3 - show-index.c | 3 - t/lib-gettext.sh | 42 ----------- t/t0200-gettext-basic.sh | 113 ---------------------------- t/t0200/test.c | 13 ---- t/t0200/test.perl | 14 ---- t/t0200/test.sh | 14 ---- t/t0201-gettext-fallbacks.sh | 49 ------------ t/t0202-gettext-perl.sh | 27 ------- t/t0202/test.pl | 107 -------------------------- t/t0203-gettext-setlocale-sanity.sh | 26 ------- t/test-lib.sh | 2 - upload-pack.c | 3 - 33 files changed, 4 insertions(+), 796 deletions(-) delete mode 100644 gettext.c delete mode 100644 gettext.h delete mode 100644 git-sh-i18n.sh delete mode 100644 perl/Git/I18N.pm delete mode 100644 po/.gitignore delete mode 100644 po/is.po delete mode 100644 t/lib-gettext.sh delete mode 100755 t/t0200-gettext-basic.sh delete mode 100644 t/t0200/test.c delete mode 100644 t/t0200/test.perl delete mode 100644 t/t0200/test.sh delete mode 100755 t/t0201-gettext-fallbacks.sh delete mode 100755 t/t0202-gettext-perl.sh delete mode 100644 t/t0202/test.pl delete mode 100755 t/t0203-gettext-setlocale-sanity.sh diff --git a/.gitignore b/.gitignore index 80ca718773..20560b810b 100644 --- a/.gitignore +++ b/.gitignore @@ -125,7 +125,6 @@ /git-rm /git-send-email /git-send-pack -/git-sh-i18n /git-sh-setup /git-shell /git-shortlog @@ -216,4 +215,3 @@ *.pdb /Debug/ /Release/ -/share/ diff --git a/INSTALL b/INSTALL index e4e7506ff4..59200b730e 100644 --- a/INSTALL +++ b/INSTALL @@ -93,18 +93,6 @@ Issues of note: history graphically, and in git-gui. If you don't want gitk or git-gui, you can use NO_TCLTK. - - A gettext library is used by default for localizing Git. The - primary target is GNU libintl, but the Solaris gettext - implementation also works. - - We need a gettext.h on the system for C code, gettext.sh (or - Solaris gettext(1)) for shell scripts, and libintl-perl for Perl - programs. - - Set NO_GETTEXT to disable localization support and make Git only - use English. Under autoconf the configure script will do this - automatically if it can't find libintl on the system. - - Some platform specific issues are dealt with Makefile rules, but depending on your specific installation, you may not have all the libraries/tools needed, or you may have diff --git a/Makefile b/Makefile index 62d526a20b..38a8b6588d 100644 --- a/Makefile +++ b/Makefile @@ -34,15 +34,6 @@ all:: # Define NO_EXPAT if you do not have expat installed. git-http-push is # not built, and you cannot push using http:// and https:// transports. # -# Define NO_GETTEXT if you don't want to build with Git with gettext -# support. Building it requires GNU libintl or another gettext -# implementation, and additionally libintl-perl at runtime. -# -# Define NEEDS_LIBINTL if you haven't set NO_GETTEXT and your system -# needs to be explicitly linked to -lintl. It's defined automatically -# on platforms where we don't expect glibc (Linux, Hurd, -# GNU/kFreeBSD), which includes libintl. -# # Define EXPATDIR=/foo/bar if your expat header and library files are in # /foo/bar/include and /foo/bar/lib directories. # @@ -292,7 +283,6 @@ infodir = share/info gitexecdir = libexec/git-core sharedir = $(prefix)/share gitwebdir = $(sharedir)/gitweb -localedir = $(sharedir)/locale template_dir = share/git-core/templates htmldir = share/doc/git-doc ifeq ($(prefix),/usr) @@ -306,7 +296,7 @@ lib = lib # DESTDIR= pathsep = : -export prefix bindir sharedir sysconfdir gitwebdir localedir +export prefix bindir sharedir sysconfdir gitwebdir CC = gcc AR = ar @@ -320,8 +310,6 @@ TCL_PATH = tclsh TCLTK_PATH = wish PTHREAD_LIBS = -lpthread PTHREAD_CFLAGS = -XGETTEXT = xgettext -MSGFMT = msgfmt GCOV = gcov export TCL_PATH TCLTK_PATH @@ -384,7 +372,6 @@ SCRIPT_SH += git-web--browse.sh SCRIPT_LIB += git-mergetool--lib SCRIPT_LIB += git-parse-remote SCRIPT_LIB += git-sh-setup -SCRIPT_LIB += git-sh-i18n SCRIPT_PERL += git-add--interactive.perl SCRIPT_PERL += git-difftool.perl @@ -557,7 +544,6 @@ LIB_H += userdiff.h LIB_H += utf8.h LIB_H += xdiff-interface.h LIB_H += xdiff/xdiff.h -LIB_H += gettext.h LIB_OBJS += abspath.o LIB_OBJS += advice.o @@ -599,9 +585,6 @@ LIB_OBJS += entry.o LIB_OBJS += environment.o LIB_OBJS += exec_cmd.o LIB_OBJS += fsck.o -ifndef NO_GETTEXT -LIB_OBJS += gettext.o -endif LIB_OBJS += graph.o LIB_OBJS += grep.o LIB_OBJS += hash.o @@ -775,14 +758,6 @@ EXTLIBS = # Platform specific tweaks # -# Platform specific defaults. Where we'd only like some feature on the -# minority of systems, e.g. if linking to a library isn't needed -# because its features are included in the GNU C library. -ifndef NO_GETTEXT - # Systems that use GNU gettext and glibc are the exception - NEEDS_LIBINTL = YesPlease -endif - # We choose to avoid "if .. else if .. else .. endif endif" # because maintaining the nesting to match is a pain. If # we had "elif" things would have been much nicer... @@ -798,13 +773,11 @@ ifeq ($(uname_S),Linux) NO_STRLCPY = YesPlease NO_MKSTEMPS = YesPlease HAVE_PATHS_H = YesPlease - NEEDS_LIBINTL = endif ifeq ($(uname_S),GNU/kFreeBSD) NO_STRLCPY = YesPlease NO_MKSTEMPS = YesPlease HAVE_PATHS_H = YesPlease - NEEDS_LIBINTL = endif ifeq ($(uname_S),UnixWare) CC = cc @@ -996,7 +969,6 @@ ifeq ($(uname_S),GNU) NO_STRLCPY=YesPlease NO_MKSTEMPS = YesPlease HAVE_PATHS_H = YesPlease - NEEDS_LIBINTL = endif ifeq ($(uname_S),IRIX) NO_SETENV = YesPlease @@ -1501,14 +1473,6 @@ ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT export GIT_TEST_CMP_USE_COPIED_CONTEXT endif -ifdef NO_GETTEXT - COMPAT_CFLAGS += -DNO_GETTEXT -endif - -ifdef NEEDS_LIBINTL - EXTLIBS += -lintl -endif - ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif @@ -1538,7 +1502,6 @@ ifndef V QUIET_BUILT_IN = @echo ' ' BUILTIN $@; QUIET_GEN = @echo ' ' GEN $@; QUIET_LNCP = @echo ' ' LN/CP $@; - QUIET_MSGFMT = @echo ' ' MSGFMT $@; QUIET_GCOV = @echo ' ' GCOV $@; QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ @@ -1568,9 +1531,7 @@ template_dir_SQ = $(subst ','\'',$(template_dir)) htmldir_SQ = $(subst ','\'',$(htmldir)) prefix_SQ = $(subst ','\'',$(prefix)) gitwebdir_SQ = $(subst ','\'',$(gitwebdir)) -sharedir_SQ = $(subst ','\'',$(sharedir)) -LOCALEDIR_SQ = $(subst ','\'',$(localedir)) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH)) @@ -1620,7 +1581,7 @@ ifndef NO_TCLTK $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all endif ifndef NO_PERL - $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all + $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all endif ifndef NO_PYTHON $(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all @@ -1666,7 +1627,6 @@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ -e 's|@@DIFF@@|$(DIFF_SQ)|' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ - -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ -e $(BROKEN_PATH_FIX) \ $@.sh >$@+ @@ -2008,21 +1968,6 @@ cscope: $(RM) cscope* $(FIND) . -name '*.[hcS]' -print | xargs cscope -b -pot: - $(XGETTEXT) --add-comments --keyword=_ --keyword=N_ --output=po/git.pot --language=C $(C_OBJ:o=c) t/t0200/test.c - $(XGETTEXT) --add-comments --join-existing --output=po/git.pot --language=Shell $(SCRIPT_SH) t/t0200/test.sh - $(XGETTEXT) --add-comments --join-existing --keyword=__ --output=po/git.pot --language=Perl $(SCRIPT_PERL) t/t0200/test.perl - -POFILES := $(wildcard po/*.po) -MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES)) -MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES)) -ifndef NO_GETTEXT -all:: $(MOFILES) -endif -share/locale/%/LC_MESSAGES/git.mo: po/%.po - @mkdir -p $(dir $@) - $(QUIET_MSGFMT)$(MSGFMT) -o $@ $< - ### Detect prefix changes TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) @@ -2052,7 +1997,6 @@ endif ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@ endif - @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK @@ -2150,11 +2094,6 @@ install: all $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)' -ifndef NO_GETTEXT - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale' - (cd share && tar cf - locale) | \ - (cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -) -endif $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install ifndef NO_PERL $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install @@ -2312,10 +2251,6 @@ ifndef NO_TCLTK $(MAKE) -C git-gui clean endif $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS -ifndef NO_GETTEXT - $(RM) po/git.pot - $(RM) -r share/ -endif .PHONY: all install clean strip .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell diff --git a/config.mak.in b/config.mak.in index 9f47aa5e10..a0c34eec15 100644 --- a/config.mak.in +++ b/config.mak.in @@ -34,11 +34,9 @@ NO_CURL=@NO_CURL@ NO_EXPAT=@NO_EXPAT@ NO_LIBGEN_H=@NO_LIBGEN_H@ HAVE_PATHS_H=@HAVE_PATHS_H@ -NO_GETTEXT=@NO_GETTEXT@ NEEDS_LIBICONV=@NEEDS_LIBICONV@ NEEDS_SOCKET=@NEEDS_SOCKET@ NEEDS_RESOLV=@NEEDS_RESOLV@ -NEEDS_LIBINTL=@NEEDS_LIBINTL@ NEEDS_LIBGEN=@NEEDS_LIBGEN@ NO_SYS_SELECT_H=@NO_SYS_SELECT_H@ NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@ diff --git a/configure.ac b/configure.ac index 1821d89d6a..56731c35c9 100644 --- a/configure.ac +++ b/configure.ac @@ -600,12 +600,6 @@ AC_CHECK_LIB([c], [basename], AC_SUBST(NEEDS_LIBGEN) test -n "$NEEDS_LIBGEN" && LIBS="$LIBS -lgen" -AC_CHECK_LIB([c], [gettext], -[NEEDS_LIBINTL=], -[NEEDS_LIBINTL=YesPlease]) -AC_SUBST(NEEDS_LIBINTL) -test -n "$NEEDS_LIBINTL" && LIBS="$LIBS -lintl" - ## Checks for header files. AC_MSG_NOTICE([CHECKS for header files]) # @@ -804,12 +798,6 @@ AC_CHECK_HEADER([paths.h], [HAVE_PATHS_H=]) AC_SUBST(HAVE_PATHS_H) # -# Define NO_GETTEXT if you don't have libintl.h -AC_CHECK_HEADER([libintl.h], -[NO_GETTEXT=], -[NO_GETTEXT=YesPlease]) -AC_SUBST(NO_GETTEXT) -# # Define NO_STRCASESTR if you don't have strcasestr. GIT_CHECK_FUNC(strcasestr, [NO_STRCASESTR=], diff --git a/daemon.c b/daemon.c index 784f8975d4..e22a2b7fa5 100644 --- a/daemon.c +++ b/daemon.c @@ -3,7 +3,6 @@ #include "exec_cmd.h" #include "run-command.h" #include "strbuf.h" -#include "gettext.h" #include @@ -976,8 +975,6 @@ int main(int argc, char **argv) gid_t gid = 0; int i; - git_setup_gettext(); - git_extract_argv0_path(argv[0]); for (i = 1; i < argc; i++) { diff --git a/fast-import.c b/fast-import.c index 8a9582687b..e2140486c9 100644 --- a/fast-import.c +++ b/fast-import.c @@ -157,7 +157,6 @@ Format of STDIN stream: #include "quote.h" #include "exec_cmd.h" #include "dir.h" -#include "gettext.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1< -#include -#include - -extern void git_setup_gettext(void) { - char *podir; - char *envdir = getenv("GIT_TEXTDOMAINDIR"); - - if (envdir) { - (void)bindtextdomain("git", envdir); - } else { - podir = (char *)system_path("share/locale"); - if (!podir) return; - (void)bindtextdomain("git", podir); - free(podir); - } - - (void)setlocale(LC_MESSAGES, ""); - (void)textdomain("git"); -} diff --git a/gettext.h b/gettext.h deleted file mode 100644 index e02939ae36..0000000000 --- a/gettext.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef GETTEXT_H -#define GETTEXT_H - -#ifdef NO_GETTEXT -static inline void git_setup_gettext(void) {} -#else -extern void git_setup_gettext(void); -#endif - -#define N_(s) (s) -#ifdef NO_GETTEXT -#define _(s) (s) -#else -#include -#define _(s) gettext(s) -#endif - -#endif diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh deleted file mode 100644 index 698a000fe5..0000000000 --- a/git-sh-i18n.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2010 Ævar Arnfjörð Bjarmason -# -# This is Git's interface to gettext.sh. Use it right after -# git-sh-setup as: -# -# . git-sh-setup -# . git-sh-i18n -# -# # For constant interface messages: -# gettext "A message for the user"; echo -# -# # To interpolate variables: -# details="oh noes" -# eval_gettext "An error occured: \$details"; echo -# -# See "info '(gettext)sh'" for the full manual. - -# Export the TEXTDOMAIN* data that we need for Git -TEXTDOMAIN=git -export TEXTDOMAIN -if [ -z "$GIT_TEXTDOMAINDIR" ] -then - TEXTDOMAINDIR="@@LOCALEDIR@@" -else - TEXTDOMAINDIR="$GIT_TEXTDOMAINDIR" -fi -export TEXTDOMAINDIR - -if test -z "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" && type gettext.sh >/dev/null 2>&1 -then - # This is GNU libintl's gettext.sh, we don't need to do anything - # else than setting up the environment and loading gettext.sh - GIT_INTERNAL_GETTEXT_SH_SCHEME=gnu - export GIT_INTERNAL_GETTEXT_SH_SCHEME - - # Try to use libintl's gettext.sh, or fall back to English if we - # can't. - . gettext.sh -elif test -z "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" && test "$(gettext -h 2>&1)" = "-h" -then - # We don't have gettext.sh, but there's a gettext binary in our - # path. This is probably Solaris or something like it which has a - # gettext implementation that isn't GNU libintl. - GIT_INTERNAL_GETTEXT_SH_SCHEME=solaris - export GIT_INTERNAL_GETTEXT_SH_SCHEME - - # Solaris has a gettext(1) but no eval_gettext(1) - eval_gettext () { - gettext_out=$(gettext "$1") - gettext_eval="printf '%s' \"$gettext_out\"" - printf "%s" "`eval \"$gettext_eval\"`" - } -else - # Since gettext.sh isn't available we'll have to define our own - # dummy pass-through functions. - - # Tell our tests that we don't have the real gettext.sh - GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough - export GIT_INTERNAL_GETTEXT_SH_SCHEME - - gettext () { - printf "%s" "$1" - } - - eval_gettext () { - gettext_eval="printf '%s' \"$1\"" - printf "%s" "`eval \"$gettext_eval\"`" - } -fi diff --git a/git.c b/git.c index f154852c76..8de48107e0 100644 --- a/git.c +++ b/git.c @@ -3,7 +3,6 @@ #include "cache.h" #include "quote.h" #include "run-command.h" -#include "gettext.h" const char git_usage_string[] = "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n" @@ -503,8 +502,6 @@ int main(int argc, const char **argv) if (!cmd) cmd = "git-help"; - git_setup_gettext(); - /* * "git-xxxx" is the same as "git xxxx", but we obviously: * diff --git a/http-backend.c b/http-backend.c index 502103d50d..14c90c2e84 100644 --- a/http-backend.c +++ b/http-backend.c @@ -7,7 +7,6 @@ #include "run-command.h" #include "string-list.h" #include "url.h" -#include "gettext.h" static const char content_type[] = "Content-Type"; static const char content_length[] = "Content-Length"; @@ -551,8 +550,6 @@ int main(int argc, char **argv) char *cmd_arg = NULL; int i; - git_setup_gettext(); - git_extract_argv0_path(argv[0]); set_die_routine(die_webcgi); diff --git a/http-fetch.c b/http-fetch.c index b889c36994..762c750d7a 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -2,7 +2,6 @@ #include "exec_cmd.h" #include "http.h" #include "walker.h" -#include "gettext.h" static const char http_fetch_usage[] = "git http-fetch " "[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"; @@ -25,8 +24,6 @@ int main(int argc, const char **argv) int get_verbosely = 0; int get_recover = 0; - git_setup_gettext(); - git_extract_argv0_path(argv[0]); while (arg < argc && argv[arg][0] == '-') { diff --git a/http-push.c b/http-push.c index fc2c5f7f65..c9bcd11697 100644 --- a/http-push.c +++ b/http-push.c @@ -10,7 +10,6 @@ #include "remote.h" #include "list-objects.h" #include "sigchain.h" -#include "gettext.h" #include @@ -1792,8 +1791,6 @@ int main(int argc, char **argv) struct remote *remote; char *rewritten_url = NULL; - git_setup_gettext(); - git_extract_argv0_path(argv[0]); repo = xcalloc(sizeof(*repo), 1); diff --git a/imap-send.c b/imap-send.c index c9dc7ecd55..71506a8dd3 100644 --- a/imap-send.c +++ b/imap-send.c @@ -25,7 +25,6 @@ #include "cache.h" #include "exec_cmd.h" #include "run-command.h" -#include "gettext.h" #ifdef NO_OPENSSL typedef void *SSL; #else @@ -1540,8 +1539,6 @@ int main(int argc, char **argv) git_extract_argv0_path(argv[0]); - git_setup_gettext(); - if (argc != 1) usage(imap_send_usage); diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm deleted file mode 100644 index 5918d68847..0000000000 --- a/perl/Git/I18N.pm +++ /dev/null @@ -1,91 +0,0 @@ -package Git::I18N; -use 5.006002; -use strict; -use warnings; -use Exporter; -use base 'Exporter'; - -our $VERSION = '0.01'; - -our @EXPORT = qw(__); -our @EXPORT_OK = @EXPORT; - -sub __bootstrap_locale_messages { - our $TEXTDOMAIN = 'git'; - our $TEXTDOMAINDIR = $ENV{GIT_TEXTDOMAINDIR} || '++LOCALEDIR++'; - - require POSIX; - POSIX->import(qw(setlocale)); - # Non-core prerequisite module - require Locale::Messages; - Locale::Messages->import(qw(:locale_h :libintl_h)); - - setlocale(LC_MESSAGES(), ''); - setlocale(LC_CTYPE(), ''); - textdomain($TEXTDOMAIN); - bindtextdomain($TEXTDOMAIN => $TEXTDOMAINDIR); - - return; -} - -BEGIN -{ - # Used by our test script to see if it should test fallbacks or - # not. - our $__HAS_LIBRARY = 1; - - local $@; - eval { __bootstrap_locale_messages() }; - if ($@) { - # Tell test.pl that we couldn't load the gettext library. - $Git::I18N::__HAS_LIBRARY = 0; - - # Just a fall-through no-op - *__ = sub ($) { $_[0] }; - } else { - *__ = \&Locale::Messages::gettext; - } -} - -1; - -__END__ - -=head1 NAME - -Git::I18N - Perl interface to Git's Gettext localizations - -=head1 SYNOPSIS - - use Git::I18N; - - print __("Welcome to Git!\n"); - - printf __("The following error occured: %s\n"), $error; - -=head1 DESCRIPTION - -Git's internal Perl interface to gettext via L. If -L can't be loaded (it's not a core module) we -provide stub passthrough fallbacks. - -This is a distilled interface to gettext, see C -for the full interface. This module implements only a small part of -it. - -=head1 FUNCTIONS - -=head2 __($) - -L's gettext function if all goes well, otherwise our -passthrough fallback function. - -=head1 AUTHOR - -Evar ArnfjErE Bjarmason - -=head1 COPYRIGHT - -Copyright 2010 Evar ArnfjErE Bjarmason - -=cut diff --git a/perl/Makefile b/perl/Makefile index b2977cd0bc..a2ffb6402d 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -5,7 +5,6 @@ makfile:=perl.mak PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) prefix_SQ = $(subst ','\'',$(prefix)) -localedir_SQ = $(subst ','\'',$(localedir)) ifndef V QUIET = @ @@ -39,7 +38,7 @@ $(makfile): ../GIT-CFLAGS Makefile echo ' echo $(instdir_SQ)' >> $@ else $(makfile): Makefile.PL ../GIT-CFLAGS - $(PERL_PATH) $< PREFIX='$(prefix_SQ)' INSTALL_BASE='' --localedir='$(localedir_SQ)' + $(PERL_PATH) $< PREFIX='$(prefix_SQ)' INSTALL_BASE='' endif # this is just added comfort for calling make directly in perl dir diff --git a/perl/Makefile.PL b/perl/Makefile.PL index 456d45bf40..0b9deca2cc 100644 --- a/perl/Makefile.PL +++ b/perl/Makefile.PL @@ -1,12 +1,4 @@ -use strict; -use warnings; use ExtUtils::MakeMaker; -use Getopt::Long; - -# Sanity: die at first unknown option -Getopt::Long::Configure qw/ pass_through /; - -GetOptions("localedir=s" => \my $localedir); sub MY::postamble { return <<'MAKE_FRAG'; @@ -24,10 +16,7 @@ endif MAKE_FRAG } -my %pm = ( - 'Git.pm' => '$(INST_LIBDIR)/Git.pm', - 'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm', -); +my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm'); # We come with our own bundled Error.pm. It's not in the set of default # Perl modules so install it if it's not available on the system yet. @@ -44,7 +33,6 @@ WriteMakefile( NAME => 'Git', VERSION_FROM => 'Git.pm', PM => \%pm, - PM_FILTER => qq[\$(PERL) -pe "s<\\Q++LOCALEDIR++\\E><$localedir>"], MAKEFILE => 'perl.mak', INSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3' ); diff --git a/po/.gitignore b/po/.gitignore deleted file mode 100644 index 221000e1b0..0000000000 --- a/po/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/*.pot diff --git a/po/is.po b/po/is.po deleted file mode 100644 index 95739f1faa..0000000000 --- a/po/is.po +++ /dev/null @@ -1,47 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: Git\n" -"PO-Revision-Date: 2010-06-05 19:06 +0000\n" -"Language-Team: Git Mailing List \n" -"Report-Msgid-Bugs-To: Git Mailing List \n" -"Last-Translator: Ævar Arnfjörð Bjarmason \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: t/t0200/test.c:4 -msgid "See git help COMMAND for more information on a specific command." -msgstr "Sjá git help SKIPUN til að sjá hjálp fyrir tiltekna skipun." - -#. TRANSLATORS: This is a test. You don't need to translate it. -#: t/t0200/test.c:9 -msgid "TEST: A C test string" -msgstr "TILRAUN: C tilraunastrengur" - -#. TRANSLATORS: This is a test. You don't need to translate it. -#: t/t0200/test.c:12 -#, c-format -msgid "TEST: A C test string %s" -msgstr "TILRAUN: C tilraunastrengur %s" - -#. TRANSLATORS: This is a test. You don't need to translate it. -#: t/t0200/test.sh:8 -msgid "TEST: A Shell test string" -msgstr "TILRAUN: Skeljartilraunastrengur" - -#. TRANSLATORS: This is a test. You don't need to translate it. -#: t/t0200/test.sh:11 -#, sh-format -msgid "TEST: A Shell test $variable" -msgstr "TILRAUN: Skeljartilraunastrengur með breytunni $variable" - -#. TRANSLATORS: This is a test. You don't need to translate it. -#: t/t0200/test.perl:8 -msgid "TEST: A Perl test string" -msgstr "TILRAUN: Perl tilraunastrengur" - -#. TRANSLATORS: This is a test. You don't need to translate it. -#: t/t0200/test.perl:11 -#, perl-format -msgid "TEST: A Perl test variable %s" -msgstr "TILRAUN: Perl tilraunastrengur með breytunni %s" diff --git a/shell.c b/shell.c index 7be826d8bc..dea4cfdd2c 100644 --- a/shell.c +++ b/shell.c @@ -2,7 +2,6 @@ #include "quote.h" #include "exec_cmd.h" #include "strbuf.h" -#include "gettext.h" #include "run-command.h" #define COMMAND_DIR "git-shell-commands" @@ -138,8 +137,6 @@ int main(int argc, char **argv) int devnull_fd; int count; - git_setup_gettext(); - /* * Always open file descriptors 0/1/2 to avoid clobbering files * in die(). It also avoids not messing up when the pipes are diff --git a/show-index.c b/show-index.c index c2f5448536..4c0ac138af 100644 --- a/show-index.c +++ b/show-index.c @@ -1,6 +1,5 @@ #include "cache.h" #include "pack.h" -#include "gettext.h" static const char show_index_usage[] = "git show-index < "; @@ -12,8 +11,6 @@ int main(int argc, char **argv) unsigned int version; static unsigned int top_index[256]; - git_setup_gettext(); - if (argc != 1) usage(show_index_usage); if (fread(top_index, 2 * 4, 1, stdin) != 1) diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh deleted file mode 100644 index f0cdd3da93..0000000000 --- a/t/lib-gettext.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2010 Ævar Arnfjörð Bjarmason -# - -. ./test-lib.sh - -GIT_TEXTDOMAINDIR="$GIT_BUILD_DIR/share/locale" -GIT_PO_PATH="$GIT_BUILD_DIR/po" -export GIT_TEXTDOMAINDIR GIT_PO_PATH - -. "$GIT_BUILD_DIR"/git-sh-i18n - -if test_have_prereq GETTEXT -then - # is_IS.UTF-8 on Solaris and FreeBSD, is_IS.utf8 on Debian - is_IS_locale=$(locale -a | sed -n '/^is_IS\.[uU][tT][fF]-*8$/{ - p - q - }') - # Export it as an environmental variable so the t0202/test.pl Perl - # test can use it too - export is_IS_locale - - if test -n "$is_IS_locale" && - test $GIT_INTERNAL_GETTEXT_SH_SCHEME != "fallthrough" - then - # Some of the tests need the reference Icelandic locale - test_set_prereq GETTEXT_LOCALE - - # Exporting for t0202/test.pl - GETTEXT_LOCALE=1 - export GETTEXT_LOCALE - say "# lib-gettext: Found '$is_IS_locale' as a is_IS UTF-8 locale" - else - say "# lib-gettext: No is_IS UTF-8 locale available" - fi -else - # Only run some tests when we don't have gettext support - test_set_prereq NO_GETTEXT - say "# lib-gettext: No GETTEXT support available" -fi diff --git a/t/t0200-gettext-basic.sh b/t/t0200-gettext-basic.sh deleted file mode 100755 index 522338d13f..0000000000 --- a/t/t0200-gettext-basic.sh +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2010 Ævar Arnfjörð Bjarmason -# - -test_description='Gettext support for Git' - -. ./lib-gettext.sh - -test_expect_success "sanity: \$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)" ' - test -n "$GIT_INTERNAL_GETTEXT_SH_SCHEME" -' - -test_expect_success 'sanity: $TEXTDOMAIN is git' ' - test $TEXTDOMAIN = "git" -' - -test_expect_success 'xgettext sanity: Perl _() strings are not extracted' ' - ! grep "A Perl string xgettext will not get" "$GIT_PO_PATH"/is.po -' - -test_expect_success 'xgettext sanity: Comment extraction with --add-comments' ' - grep "TRANSLATORS: This is a test" "$TEST_DIRECTORY"/t0200/* | wc -l >expect && - grep "TRANSLATORS: This is a test" "$GIT_PO_PATH"/is.po | wc -l >actual && - test_cmp expect actual -' - -test_expect_success 'xgettext sanity: Comment extraction with --add-comments stops at statements' ' - ! grep "This is a phony" "$GIT_PO_PATH"/is.po && - ! grep "the above comment" "$GIT_PO_PATH"/is.po -' - -test_expect_success GETTEXT 'sanity: $TEXTDOMAINDIR exists without NO_GETTEXT=YesPlease' ' - test -d "$TEXTDOMAINDIR" && - test "$TEXTDOMAINDIR" = "$GIT_TEXTDOMAINDIR" -' - -test_expect_success GETTEXT 'sanity: Icelandic locale was compiled' ' - test -f "$TEXTDOMAINDIR/is/LC_MESSAGES/git.mo" -' - -test_expect_success NO_GETTEXT "sanity: \$TEXTDOMAINDIR doesn't exists with NO_GETTEXT=YesPlease" ' - ! test -d "$TEXTDOMAINDIR" && - test "$TEXTDOMAINDIR" = "$GIT_TEXTDOMAINDIR" -' - -# TODO: When we have more locales, generalize this to test them -# all. Maybe we'll need a dir->locale map for that. -test_expect_success GETTEXT_LOCALE 'sanity: gettext("") metadata is OK' ' - # Return value may be non-zero - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "" >zero-expect && - grep "Project-Id-Version: Git" zero-expect && - grep "Git Mailing List " zero-expect && - grep "Content-Type: text/plain; charset=UTF-8" zero-expect && - grep "Content-Transfer-Encoding: 8bit" zero-expect -' - -test_expect_success GETTEXT_LOCALE 'sanity: gettext(unknown) is passed through' ' - printf "This is not a translation string" >expect && - gettext "This is not a translation string" >actual && - eval_gettext "This is not a translation string" >actual && - test_cmp expect actual -' - -# xgettext from C -test_expect_success GETTEXT_LOCALE 'xgettext: C extraction of _() and N_() strings' ' - printf "TILRAUN: C tilraunastrengur" >expect && - printf "\n" >>expect && - printf "Sjá git help SKIPUN til að sjá hjálp fyrir tiltekna skipun." >>expect && - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A C test string" >actual && - printf "\n" >>actual && - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "See git help COMMAND for more information on a specific command." >>actual && - test_cmp expect actual -' - -test_expect_success GETTEXT_LOCALE 'xgettext: C extraction with %s' ' - printf "TILRAUN: C tilraunastrengur %%s" >expect && - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A C test string %s" >actual && - test_cmp expect actual -' - -# xgettext from Shell -test_expect_success GETTEXT_LOCALE 'xgettext: Shell extraction' ' - printf "TILRAUN: Skeljartilraunastrengur" >expect && - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A Shell test string" >actual && - test_cmp expect actual -' - -test_expect_success GETTEXT_LOCALE 'xgettext: Shell extraction with $variable' ' - printf "TILRAUN: Skeljartilraunastrengur með breytunni a var i able" >x-expect && - LANGUAGE=is LC_ALL="$is_IS_locale" variable="a var i able" eval_gettext "TEST: A Shell test \$variable" >x-actual && - test_cmp x-expect x-actual -' - -# xgettext from Perl -test_expect_success GETTEXT_LOCALE 'xgettext: Perl extraction' ' - printf "TILRAUN: Perl tilraunastrengur" >expect && - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A Perl test string" >actual && - test_cmp expect actual -' - -test_expect_success GETTEXT_LOCALE 'xgettext: Perl extraction with %s' ' - printf "TILRAUN: Perl tilraunastrengur með breytunni %%s" >expect && - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: A Perl test variable %s" >actual && - test_cmp expect actual -' - -test_expect_success GETTEXT_LOCALE 'sanity: Some gettext("") data for real locale' ' - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "" >real-locale && - test -s real-locale -' - -test_done diff --git a/t/t0200/test.c b/t/t0200/test.c deleted file mode 100644 index 93373b38f7..0000000000 --- a/t/t0200/test.c +++ /dev/null @@ -1,13 +0,0 @@ -/* This is a phony C program that's only here to test xgettext message extraction */ - -const char help[] = - N_("See 'git help COMMAND' for more information on a specific command."); - -int main(void) -{ - /* TRANSLATORS: This is a test. You don't need to translate it. */ - puts(_("TEST: A C test string")); - - /* TRANSLATORS: This is a test. You don't need to translate it. */ - printf(_("TEST: A C test string %s"), "variable"); -} diff --git a/t/t0200/test.perl b/t/t0200/test.perl deleted file mode 100644 index 36fba341ba..0000000000 --- a/t/t0200/test.perl +++ /dev/null @@ -1,14 +0,0 @@ -# This is a phony Perl program that's only here to test xgettext -# message extraction - -# so the above comment won't be folded into the next one by xgettext -1; - -# TRANSLATORS: This is a test. You don't need to translate it. -print __("TEST: A Perl test string"); - -# TRANSLATORS: This is a test. You don't need to translate it. -printf __("TEST: A Perl test variable %s"), "moo"; - -# TRANSLATORS: If you see this, Git has a bug -print _"TEST: A Perl string xgettext will not get"; diff --git a/t/t0200/test.sh b/t/t0200/test.sh deleted file mode 100644 index 022d607f4c..0000000000 --- a/t/t0200/test.sh +++ /dev/null @@ -1,14 +0,0 @@ -# This is a phony Shell program that's only here to test xgettext -# message extraction - -# so the above comment won't be folded into the next one by xgettext -echo - -# TRANSLATORS: This is a test. You don't need to translate it. -gettext "TEST: A Shell test string" - -# TRANSLATORS: This is a test. You don't need to translate it. -eval_gettext "TEST: A Shell test \$variable" - -# TRANSLATORS: If you see this, Git has a bug -_("TEST: A Shell string xgettext won't get") diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh deleted file mode 100755 index 47ce4f6b6e..0000000000 --- a/t/t0201-gettext-fallbacks.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2010 Ævar Arnfjörð Bjarmason -# - -test_description='Gettext Shell fallbacks' - -GIT_INTERNAL_GETTEXT_TEST_FALLBACKS=YesPlease -export GIT_INTERNAL_GETTEXT_TEST_FALLBACKS - -. ./lib-gettext.sh - -test_expect_success "sanity: \$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)" ' - test -n "$GIT_INTERNAL_GETTEXT_SH_SCHEME" -' - -test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_TEST_FALLBACKS is set' ' - test -n "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" -' - -test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME" is fallthrough' ' - test "$GIT_INTERNAL_GETTEXT_SH_SCHEME" = "fallthrough" -' - -test_expect_success 'gettext: our gettext() fallback has pass-through semantics' ' - printf "test" >expect && - gettext "test" >actual && - test_cmp expect actual && - printf "test more words" >expect && - gettext "test more words" >actual && - test_cmp expect actual -' - -test_expect_success 'eval_gettext: our eval_gettext() fallback has pass-through semantics' ' - printf "test" >expect && - eval_gettext "test" >actual && - test_cmp expect actual && - printf "test more words" >expect && - eval_gettext "test more words" >actual && - test_cmp expect actual -' - -test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables' ' - printf "test YesPlease" >expect && - eval_gettext "test \$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" >actual && - test_cmp expect actual -' - -test_done diff --git a/t/t0202-gettext-perl.sh b/t/t0202-gettext-perl.sh deleted file mode 100755 index 428ebb0080..0000000000 --- a/t/t0202-gettext-perl.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2010 Ævar Arnfjörð Bjarmason -# - -test_description='Perl gettext interface (Git::I18N)' - -. ./lib-gettext.sh - -if ! test_have_prereq PERL; then - skip_all='skipping perl interface tests, perl not available' - test_done -fi - -"$PERL_PATH" -MTest::More -e 0 2>/dev/null || { - skip_all="Perl Test::More unavailable, skipping test" - test_done -} - -# The external test will outputs its own plan -test_external_has_tap=1 - -test_external_without_stderr \ - 'Perl Git::I18N API' \ - "$PERL_PATH" "$TEST_DIRECTORY"/t0202/test.pl - -test_done diff --git a/t/t0202/test.pl b/t/t0202/test.pl deleted file mode 100644 index c2055fa8de..0000000000 --- a/t/t0202/test.pl +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/perl -use 5.006002; -use lib (split(/:/, $ENV{GITPERLLIB})); -use warnings; -use strict; -use Test::More tests => 9; -use Git::I18N; -use POSIX qw(:locale_h); - -my $has_gettext_library = $Git::I18N::__HAS_LIBRARY; - -ok(1, "Testing Git::I18N version $Git::I18N::VERSION with " . - ($has_gettext_library - ? "Locale::Messages version $Locale::Messages::VERSION" - : "NO Perl gettext library")); -ok(1, "Git::I18N is located at $INC{'Git/I18N.pm'}"); - -ok($Git::I18N::VERSION, 'sanity: Git::I18N defines a $VERSION'); -{ - my $exports = @Git::I18N::EXPORT; - ok($exports, "sanity: Git::I18N has $exports export(s)"); -} -is_deeply(\@Git::I18N::EXPORT, \@Git::I18N::EXPORT_OK, "sanity: Git::I18N exports everything by default"); - -# prototypes -{ - # Add prototypes here when modifying the public interface to add - # more gettext wrapper functions. - my %prototypes = (qw( - __ $ - )); - while (my ($sub, $proto) = each %prototypes) { - is(prototype(\&{"Git::I18N::$sub"}), $proto, "sanity: $sub has a $proto prototype"); - } -} - -# Test basic passthrough in the C locale -{ - local $ENV{LANGUAGE} = 'C'; - local $ENV{LC_ALL} = 'C'; - local $ENV{LANG} = 'C'; - - my ($got, $expect) = (('TEST: A Perl test string') x 2); - - is(__($got), $expect, "Passing a string through __() in the C locale works"); -} - -# Test a basic message on different locales -SKIP: { - unless ($ENV{GETTEXT_LOCALE}) { - # Can't reliably test __() with a non-C locales because the - # required locales may not be installed on the system. - # - # We test for these anyway as part of the shell - # tests. Skipping these here will eliminate failures on odd - # platforms with incomplete locale data. - - skip "GETTEXT_LOCALE must be set by lib-gettext.sh for exhaustive Git::I18N tests", 2; - } - - # The is_IS UTF-8 locale passed from lib-gettext.sh - my $is_IS_locale = $ENV{is_IS_locale}; - - my $test = sub { - my ($got, $expect, $msg, $locale) = @_; - # Maybe this system doesn't have the locale we're trying to - # test. - my $locale_ok = setlocale(LC_ALL, $locale); - is(__($got), $expect, "$msg a gettext library + <$locale> locale <$got> turns into <$expect>"); - }; - - my $env_C = sub { - $ENV{LANGUAGE} = 'C'; - $ENV{LC_ALL} = 'C'; - }; - - my $env_is = sub { - $ENV{LANGUAGE} = 'is'; - $ENV{LC_ALL} = $is_IS_locale; - }; - - # Translation's the same as the original - my ($got, $expect) = (('TEST: A Perl test string') x 2); - - if ($has_gettext_library) { - { - local %ENV; $env_C->(); - $test->($got, $expect, "With", 'C'); - } - - { - my ($got, $expect) = ($got, 'TILRAUN: Perl tilraunastrengur'); - local %ENV; $env_is->(); - $test->($got, $expect, "With", $is_IS_locale); - } - } else { - { - local %ENV; $env_C->(); - $test->($got, $expect, "Without", 'C'); - } - - { - local %ENV; $env_is->(); - $test->($got, $expect, "Without", 'is'); - } - } -} diff --git a/t/t0203-gettext-setlocale-sanity.sh b/t/t0203-gettext-setlocale-sanity.sh deleted file mode 100755 index a212460081..0000000000 --- a/t/t0203-gettext-setlocale-sanity.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2010 Ævar Arnfjörð Bjarmason -# - -test_description="The Git C functions aren't broken by setlocale(3)" - -. ./lib-gettext.sh - -test_expect_success 'git show a ISO-8859-1 commit under C locale' ' - . "$TEST_DIRECTORY"/t3901-8859-1.txt && - test_commit "iso-c-commit" iso-under-c && - git show >out 2>err && - ! test -s err && - grep -q "iso-c-commit" out -' - -test_expect_success GETTEXT_LOCALE 'git show a ISO-8859-1 commit under a UTF-8 locale' ' - . "$TEST_DIRECTORY"/t3901-8859-1.txt && - test_commit "iso-utf8-commit" iso-under-utf8 && - LANGUAGE=is LC_ALL="$is_IS_locale" git show >out 2>err && - ! test -s err && - grep -q "iso-utf8-commit" out -' - -test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 3fcb272923..dff5e25ae6 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -37,7 +37,6 @@ ORIGINAL_TERM=$TERM # For repeatability, reset the environment to known value. LANG=C LC_ALL=C -LANGUAGE=C PAGER=cat TZ=UTC TERM=dumb @@ -962,7 +961,6 @@ esac test -z "$NO_PERL" && test_set_prereq PERL test -z "$NO_PYTHON" && test_set_prereq PYTHON -test -z "$NO_GETTEXT" && test_set_prereq GETTEXT # test whether the filesystem supports symbolic links ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS diff --git a/upload-pack.c b/upload-pack.c index ce27a1a362..92f9530c65 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -10,7 +10,6 @@ #include "revision.h" #include "list-objects.h" #include "run-command.h" -#include "gettext.h" static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=nn] "; @@ -683,8 +682,6 @@ int main(int argc, char **argv) int i; int strict = 0; - git_setup_gettext(); - git_extract_argv0_path(argv[0]); read_replace_refs = 0; From 496b35e7e06e054de769c3f9131381fb3304b936 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 29 Aug 2010 17:50:32 +0200 Subject: [PATCH 1171/3720] fetch/pull: Recursively fetch populated submodules Until now you had to call "git submodule update" (without -N|--no-fetch option) or something like "git submodule foreach git fetch" to fetch new commits in populated submodules from their remote. This could lead to "(commits not present)" messages in the output of "git diff --submodule" (and in "git gui" and "gitk") after fetching or pulling new commits in the superproject and is an obstacle for implementing recursive checkout of submodules. This patch recursively fetches each populated submodule from the url configured in the .git/config of the submodule at the end of each "git fetch" or during "git pull" in the superproject. This new behavior can be disabled by using the new --no-recursive option. t7403 had to be changed to use the --no-recursive option for pull. Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- Documentation/fetch-options.txt | 5 +++ builtin/fetch.c | 11 +++++- git-pull.sh | 10 ++++-- submodule.c | 43 +++++++++++++++++++++- submodule.h | 2 ++ t/t5526-fetch-submodules.sh | 64 +++++++++++++++++++++++++++++++++ t/t7403-submodule-sync.sh | 2 +- 7 files changed, 132 insertions(+), 5 deletions(-) create mode 100755 t/t5526-fetch-submodules.sh diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 9333c42c55..8cc96c922e 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -60,6 +60,11 @@ endif::git-pull[] flag lets all tags and their associated objects be downloaded. +--[no-]recursive:: + By default new commits of all populated submodules will be fetched + too. This option can be used to disable/enable recursive fetching of + submodules. + -u:: --update-head-ok:: By default 'git fetch' refuses to update the head which diff --git a/builtin/fetch.c b/builtin/fetch.c index ea14d5dc6b..17839b4c2b 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -12,6 +12,7 @@ #include "parse-options.h" #include "sigchain.h" #include "transport.h" +#include "submodule.h" static const char * const builtin_fetch_usage[] = { "git fetch [] [ [...]]", @@ -27,7 +28,7 @@ enum { TAGS_SET = 2 }; -static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity; +static int all, append, dry_run, force, keep, multiple, prune, recursive = -1, update_head_ok, verbosity; static int progress; static int tags = TAGS_DEFAULT; static const char *depth; @@ -53,6 +54,8 @@ static struct option builtin_fetch_options[] = { "do not fetch all tags (--no-tags)", TAGS_UNSET), OPT_BOOLEAN('p', "prune", &prune, "prune tracking branches no longer on remote"), + OPT_BOOLEAN(0, "recursive", &recursive, + "control recursive fetching of submodules"), OPT_BOOLEAN(0, "dry-run", &dry_run, "dry run"), OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"), @@ -919,6 +922,12 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) } } + if (!result && recursive) { + gitmodules_config(); + git_config(submodule_config, NULL); + result = fetch_populated_submodules(); + } + /* All names were strdup()ed or strndup()ed */ list.strdup_strings = 1; string_list_clear(&list, 0); diff --git a/git-pull.sh b/git-pull.sh index 8eb74d45de..4bc8a60c64 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -38,7 +38,7 @@ test -z "$(git ls-files -u)" || die_conflict test -f "$GIT_DIR/MERGE_HEAD" && die_merge strategy_args= diffstat= no_commit= squash= no_ff= ff_only= -log_arg= verbosity= progress= +log_arg= verbosity= progress= recursive= merge_args= curr_branch=$(git symbolic-ref -q HEAD) curr_branch_short="${curr_branch#refs/heads/}" @@ -105,6 +105,12 @@ do --no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase) rebase=false ;; + --recursive) + recursive=--recursive + ;; + --no-recursive) + recursive=--no-recursive + ;; --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run) dry_run=--dry-run ;; @@ -220,7 +226,7 @@ test true = "$rebase" && { done } orig_head=$(git rev-parse -q --verify HEAD) -git fetch $verbosity $progress $dry_run --update-head-ok "$@" || exit 1 +git fetch $verbosity $progress $dry_run $recursive --update-head-ok "$@" || exit 1 test -z "$dry_run" || exit 0 curr_head=$(git rev-parse -q --verify HEAD) diff --git a/submodule.c b/submodule.c index 91a4758747..e4f2419d6b 100644 --- a/submodule.c +++ b/submodule.c @@ -63,7 +63,7 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, } } -static int submodule_config(const char *var, const char *value, void *cb) +int submodule_config(const char *var, const char *value, void *cb) { if (!prefixcmp(var, "submodule.")) return parse_submodule_config_option(var, value); @@ -229,6 +229,47 @@ void show_submodule_summary(FILE *f, const char *path, strbuf_release(&sb); } +int fetch_populated_submodules() +{ + int result = 0; + struct child_process cp; + const char *argv[] = { + "fetch", + NULL, + }; + struct string_list_item *name_for_path; + const char *work_tree = get_git_work_tree(); + if (!work_tree) + return 0; + + memset(&cp, 0, sizeof(cp)); + cp.argv = argv; + cp.env = local_repo_env; + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.out = -1; + + for_each_string_list_item(name_for_path, &config_name_for_path) { + struct strbuf submodule_path = STRBUF_INIT; + struct strbuf submodule_git_dir = STRBUF_INIT; + const char *git_dir; + strbuf_addf(&submodule_path, "%s/%s", work_tree, name_for_path->string); + strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf); + git_dir = read_gitfile_gently(submodule_git_dir.buf); + if (!git_dir) + git_dir = submodule_git_dir.buf; + if (is_directory(git_dir)) { + printf("Fetching submodule %s\n", name_for_path->string); + cp.dir = submodule_path.buf; + if (run_command(&cp)) + result = 1; + } + strbuf_release(&submodule_path); + strbuf_release(&submodule_git_dir); + } + return result; +} + unsigned is_submodule_modified(const char *path, int ignore_untracked) { ssize_t len; diff --git a/submodule.h b/submodule.h index 386f410a66..380878cc79 100644 --- a/submodule.h +++ b/submodule.h @@ -5,6 +5,7 @@ struct diff_options; void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, const char *path); +int submodule_config(const char *var, const char *value, void *cb); void gitmodules_config(); int parse_submodule_config_option(const char *var, const char *value); void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *); @@ -12,6 +13,7 @@ void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], unsigned dirty_submodule, const char *del, const char *add, const char *reset); +int fetch_populated_submodules(); unsigned is_submodule_modified(const char *path, int ignore_untracked); int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20], const unsigned char a[20], const unsigned char b[20]); diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh new file mode 100755 index 0000000000..da5d5fd6be --- /dev/null +++ b/t/t5526-fetch-submodules.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# Copyright (c) 2010, Jens Lehmann + +test_description='Recursive "git fetch" for submodules' + +. ./test-lib.sh + +pwd=$(pwd) + +add_upstream_commit() { + ( + cd submodule && + head1=$(git rev-parse --short HEAD) && + echo new >> subfile && + test_tick && + git add subfile && + git commit -m new subfile && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/submodule" > ../expect.err + echo " $head1..$head2 master -> origin/master" >> ../expect.err + ) +} + +test_expect_success setup ' + mkdir submodule && + ( + cd submodule && + git init && + echo subcontent > subfile && + git add subfile && + git commit -m new subfile + ) && + git submodule add "$pwd/submodule" submodule && + git commit -am initial && + git clone . downstream && + ( + cd downstream && + git submodule init && + git submodule update + ) && + echo "Fetching submodule submodule" > expect.out +' + +test_expect_success "fetch recurses into submodules" ' + add_upstream_commit && + ( + cd downstream && + git fetch >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "fetch --no-recursive only fetches superproject" ' + add_upstream_commit && + ( + cd downstream && + git fetch --no-recursive >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_done diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index bade2179b1..3c051c1055 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -50,7 +50,7 @@ test_expect_success 'change submodule url' ' test_expect_success '"git submodule sync" should update submodule URLs' ' (cd super-clone && - git pull && + git pull --no-recursive && git submodule sync ) && test -d "$(git config -f super-clone/submodule/.git/config \ From 4e0fb797bf18164fe9ca779e2c5480c7411e8d09 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Mon, 30 Aug 2010 19:37:47 +0200 Subject: [PATCH 1172/3720] Submodules: Add the new "fetch" config option for fetch and pull The new boolean "fetch" config option controls the default behavior for "git fetch" and "git pull". It specifies if these commands should recurse into submodules and fetch new commits there too and can be set separately for each submodule. The .gitmodules file is parsed for "submodule..fetch" entries before looking for them in .git/config. Thus settings found in .git/config will override those from .gitmodules, thereby allowing the local developer to ignore settings given by the remote side while also letting upstream set defaults for those users who don't have special needs. This configuration can be overridden by the command line option "--[no-]recursive" of "git fetch" and "git pull". Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- Documentation/config.txt | 6 +++++ Documentation/fetch-options.txt | 3 ++- Documentation/gitmodules.txt | 8 +++++++ builtin/fetch.c | 14 ++++++++---- submodule.c | 19 +++++++++++++++- submodule.h | 2 +- t/t5526-fetch-submodules.sh | 40 +++++++++++++++++++++++++++++++++ 7 files changed, 85 insertions(+), 7 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 05ec3fed89..7ab00fb5c8 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1763,6 +1763,12 @@ submodule..update:: URL and other values found in the `.gitmodules` file. See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. +submodule..fetch:: + A boolean to enable/disable recursive fetching of this submodule. It can + be overriden by using the --[no-]recursive command line option to "git + fetch" and "git pull". This setting overrides any setting made in + .gitmodules for this submodule. + submodule..ignore:: Defines under what circumstances "git status" and the diff family show a submodule as modified. When set to "all", it will never be considered diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 8cc96c922e..f5734b4769 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -63,7 +63,8 @@ endif::git-pull[] --[no-]recursive:: By default new commits of all populated submodules will be fetched too. This option can be used to disable/enable recursive fetching of - submodules. + submodules regardless of the 'fetch' configuration setting (see + linkgit:git-config[1] or linkgit:gitmodules[5]). -u:: --update-head-ok:: diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index bcffd95ada..febfef46a5 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -44,6 +44,14 @@ submodule..update:: This config option is overridden if 'git submodule update' is given the '--merge' or '--rebase' options. +submodule..fetch:: + A boolean to enable/disable recursive fetching of this submodule. + If this option is also present in the submodules entry in .git/config of + the superproject, the setting there will override the one found in + .gitmodules. + Both settings can be overriden on the command line by using the + "--[no-]recursive" option to "git fetch" and "git pull".. + submodule..ignore:: Defines under what circumstances "git status" and the diff family show a submodule as modified. When set to "all", it will never be considered diff --git a/builtin/fetch.c b/builtin/fetch.c index 17839b4c2b..0a1afe9870 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -28,7 +28,13 @@ enum { TAGS_SET = 2 }; -static int all, append, dry_run, force, keep, multiple, prune, recursive = -1, update_head_ok, verbosity; +enum { + RECURSIVE_UNSET = 0, + RECURSIVE_DEFAULT = 1, + RECURSIVE_SET = 2 +}; + +static int all, append, dry_run, force, keep, multiple, prune, recursive = RECURSIVE_DEFAULT, update_head_ok, verbosity; static int progress; static int tags = TAGS_DEFAULT; static const char *depth; @@ -54,8 +60,8 @@ static struct option builtin_fetch_options[] = { "do not fetch all tags (--no-tags)", TAGS_UNSET), OPT_BOOLEAN('p', "prune", &prune, "prune tracking branches no longer on remote"), - OPT_BOOLEAN(0, "recursive", &recursive, - "control recursive fetching of submodules"), + OPT_SET_INT(0, "recursive", &recursive, + "control recursive fetching of submodules", RECURSIVE_SET), OPT_BOOLEAN(0, "dry-run", &dry_run, "dry run"), OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"), @@ -925,7 +931,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (!result && recursive) { gitmodules_config(); git_config(submodule_config, NULL); - result = fetch_populated_submodules(); + result = fetch_populated_submodules(recursive == RECURSIVE_SET); } /* All names were strdup()ed or strndup()ed */ diff --git a/submodule.c b/submodule.c index e4f2419d6b..23806383fd 100644 --- a/submodule.c +++ b/submodule.c @@ -10,6 +10,7 @@ #include "string-list.h" struct string_list config_name_for_path; +struct string_list config_fetch_for_name; struct string_list config_ignore_for_name; static int add_submodule_odb(const char *path) @@ -100,6 +101,14 @@ int parse_submodule_config_option(const char *var, const char *value) config = string_list_append(&config_name_for_path, xstrdup(value)); config->util = strbuf_detach(&submodname, NULL); strbuf_release(&submodname); + } else if ((len > 5) && !strcmp(var + len - 6, ".fetch")) { + strbuf_add(&submodname, var, len - 6); + config = unsorted_string_list_lookup(&config_fetch_for_name, submodname.buf); + if (!config) + config = string_list_append(&config_fetch_for_name, + strbuf_detach(&submodname, NULL)); + config->util = git_config_bool(var, value) ? (void *)1 : NULL; + strbuf_release(&submodname); } else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { if (strcmp(value, "untracked") && strcmp(value, "dirty") && strcmp(value, "all") && strcmp(value, "none")) { @@ -229,7 +238,7 @@ void show_submodule_summary(FILE *f, const char *path, strbuf_release(&sb); } -int fetch_populated_submodules() +int fetch_populated_submodules(int forced) { int result = 0; struct child_process cp; @@ -253,6 +262,14 @@ int fetch_populated_submodules() struct strbuf submodule_path = STRBUF_INIT; struct strbuf submodule_git_dir = STRBUF_INIT; const char *git_dir; + + if (!forced) { + struct string_list_item *fetch_option; + fetch_option = unsorted_string_list_lookup(&config_fetch_for_name, name_for_path->util); + if (fetch_option && !fetch_option->util) + continue; + } + strbuf_addf(&submodule_path, "%s/%s", work_tree, name_for_path->string); strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf); git_dir = read_gitfile_gently(submodule_git_dir.buf); diff --git a/submodule.h b/submodule.h index 380878cc79..9e6257edf1 100644 --- a/submodule.h +++ b/submodule.h @@ -13,7 +13,7 @@ void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], unsigned dirty_submodule, const char *del, const char *add, const char *reset); -int fetch_populated_submodules(); +int fetch_populated_submodules(int forced); unsigned is_submodule_modified(const char *path, int ignore_untracked); int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20], const unsigned char a[20], const unsigned char b[20]); diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index da5d5fd6be..489ef1a933 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -52,6 +52,46 @@ test_expect_success "fetch recurses into submodules" ' ' test_expect_success "fetch --no-recursive only fetches superproject" ' + ( + cd downstream && + git fetch --no-recursive >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "using fetch=false in .gitmodules only fetches superproject" ' + ( + cd downstream && + git config -f .gitmodules submodule.submodule.fetch false && + git fetch >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "--recursive overrides .gitmodules config" ' + add_upstream_commit && + ( + cd downstream && + git fetch --recursive >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "using fetch=true in .git/config overrides setting in .gitmodules" ' + add_upstream_commit && + ( + cd downstream && + git config submodule.submodule.fetch true && + git fetch >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "--no-recursive overrides fetch setting from .git/config" ' add_upstream_commit && ( cd downstream && From b20047ba1c54dcf9ae020958e483c5841ad1c54b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 1173/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 38a8b6588d..367576c615 100644 --- a/Makefile +++ b/Makefile @@ -1956,6 +1956,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1963,6 +1964,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 370a7f2608a54243598022e086074b754edd81f9 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 1174/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 788486b7b04fb648565e43c74d3f5354a968246f Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1175/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From b0595c7d5eed6d0ce664fb409929231fa9287123 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1176/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index cda6721013..a92f340d57 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index be02a422d1..d9726930e6 100644 --- a/cache.h +++ b/cache.h @@ -551,6 +551,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f2d9e1fd97..9f6df8762d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index cdcf5836c6..42e94f991b 100644 --- a/config.c +++ b/config.c @@ -595,6 +595,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index eeb26876a1..34ec3ac023 100644 --- a/environment.c +++ b/environment.c @@ -54,6 +54,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 877096ecb0..dae7686fc2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -510,4 +510,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From f50de2eaf4354470c1fb7e129f83679354499708 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1177/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 9f6df8762d..884f698873 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From c70cca42b5211a37b107d69d7f64a61e3ac75e55 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1178/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 8f8418fe2e2842b241716e430bf62506d87621c3 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 1179/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..1eaa83f686 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NONMINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NONMINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/test-lib.sh b/t/test-lib.sh index dff5e25ae6..0d12ac9965 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -956,6 +956,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From be2d9949c81b5b240e6376ba8e67d2f03cb61e7a Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1180/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index bb104895a9..76981e563d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1213,9 +1213,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2015,7 +2012,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2027,12 +2024,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2053,18 +2057,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2085,20 +2086,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From c0c8af96f7db8da371616cf463bb5da7c742a144 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1181/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 884f698873..208b9f987e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From cd18d25a5ac12c495ec23523b5cefbcaa4ea4572 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1182/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 208b9f987e..14be1bbb2e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1248,7 +1264,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 9229029bb52cbed0b0e18922e0603e150c82c170 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1183/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 14be1bbb2e..d813203ea0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1305,6 +1358,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 7e4ca34da0f0b7cd836ee352d64a521e0c90c7fd Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1184/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d813203ea0..ef23b6274e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 7cacb06dec08ab2d59c43d26fb308bc09d9bb28a Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1185/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 76981e563d..ccbed506ad 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 91c47c7af0bf823a607386d94df2437630f4c413 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1186/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 4bdab4f285d035db41567c23e921a6902bc303de Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1187/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ef23b6274e..d770c2d00c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 5930ea834e9129236e2e731e9f2e26251c9c26d9 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1188/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d770c2d00c..12f230b665 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1590,6 +1590,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1599,9 +1600,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From d8384cef2a1cc8d5f754dad1ac7db4f6e90a49d4 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1189/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7fe8883ae0..28f67ce1d4 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -318,4 +318,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 0d12ac9965..282943f1d3 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -951,6 +951,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 83553395660a3366c42c5a2132528b02743ce46c Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1190/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 12f230b665..0c67afd55e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 3069b65eea55490be55e0fb85e23a6e067ee3d43 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 1191/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0c67afd55e..2718b7d649 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From ff1f4479597cb031e6a4c5c610cd9ebfbba47ed5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 1192/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..6b9f76a27d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 85e22a76aa2d6d3ed57e0ad485a4f7fbd3f8167b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1193/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 18b07d9d36..0182d168ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 1ff44ac1dd94fffc6eaebe17e92f07d7abd35ba7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1194/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index a92f340d57..666ae1414b 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1597,6 +1597,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 230ed6a684c4415d650ef5127fa5d85dd73416f1 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1195/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2718b7d649..62e7ba11ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 5bdb4f75c4c51c4ddac2087621c220e53c8ec712 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1196/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 6dab3bf6a7..53f89d6cd2 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1017,7 +1017,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 41cc495a7c539acef7aa981586fad1cb3a22654c Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1197/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 53f89d6cd2..e157e4b469 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1103,7 +1103,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 07664f5f0d1c79a64045233d872d2b886ba13374 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1198/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 62e7ba11ce..ec26ba6655 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 110b20615cf8b5a30751b335330adf76850caa99 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1199/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index ec26ba6655..c058b22654 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1731,3 +1731,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 42e94f991b..1d2410e512 100644 --- a/config.c +++ b/config.c @@ -804,7 +804,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index dae7686fc2..1e4038d61f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -514,4 +514,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index a2c9d1e24a..30d66a94c0 100644 --- a/path.c +++ b/path.c @@ -353,7 +353,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 5e057cab900748edee87c268d8924ca3a2b63634 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1200/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 282943f1d3..821bdc88fe 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -851,6 +851,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 499df4ca8b541fe2837ab46f1dae4574952e9f64 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1201/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 3437fbdcf674d530a8dad2a0a32f7bac20a24a1e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1202/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From 7c352cbfb5f1a37e0dbbab3903a8bf03054903a9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1203/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6b9f76a27d..ae9fc2346d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 292701a022b72f5d96323de4a78fd74693745a68 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1204/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 821bdc88fe..68e7f8e0b1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From ace097c64d1f070ae72a67344d206c6bc318d964 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1205/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From ac5d4a5aecc5311c6267e71fb36cad3966e8d721 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1206/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index d9726930e6..ec0d3fc317 100644 --- a/cache.h +++ b/cache.h @@ -720,7 +720,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index c058b22654..4dc751d047 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1749,3 +1749,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 1e4038d61f..cc469b2053 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -179,6 +179,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 30d66a94c0..0e560cabac 100644 --- a/path.c +++ b/path.c @@ -768,10 +768,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 1a96f110a295981f81ad2d690bbafe0921b3ab33 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1207/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 20104005be2090bdaaf951e843e6691b51b1c8d7 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1208/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4dc751d047..f96d8367b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1752,23 +1752,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 65f500d65a0553716f92116953755180f9171ec1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 17:40:44 +0200 Subject: [PATCH 1209/3720] Make sure that git_getpass() never returns NULL The result of git_getpass() is used without checking for NULL, so let's just die() instead of returning NULL. Signed-off-by: Johannes Schindelin --- connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 02e738a014..d3e967fcd9 100644 --- a/connect.c +++ b/connect.c @@ -628,8 +628,12 @@ char *git_getpass(const char *prompt) askpass = getenv("GIT_ASKPASS"); - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; From 77b5d7d9edcb2135b2c812a9e9a64e56d5869ac7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1210/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ccbed506ad..8eeebe06e2 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From d5279efdf70c1fc5dc61f19c2bc1a59c600d0e0a Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1211/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 3d358b696f86290c84f66ac535d6242039180e7a Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1212/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f96d8367b2..b0ad9192fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -701,11 +701,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 71b4329defdb1f142fff1f3132b432c340080d50 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1213/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 246e2b089e316b0e7707f6fdf6c40d73868a5a2d Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1214/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 8cc62199c66c0539e65b5e4877439924f72564f9 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1215/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From 85e897d2252e3fc617b442c6fe26854bfe616f4b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1216/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 15f85ea83bbc4031cd7a98f65c1f6b435e4387f6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Aug 2010 12:04:40 +0200 Subject: [PATCH 1217/3720] Fix typo in pack-objects' usage Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0e81673118..3756cf36ee 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -30,7 +30,7 @@ static const char pack_usage[] = " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n" " [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n" " [--reflog] [--stdout | base-name] [--include-tag]\n" - " [--keep-unreachable | --unpack-unreachable \n" + " [--keep-unreachable | --unpack-unreachable]\n" " [ Date: Thu, 26 Aug 2010 14:34:07 +0200 Subject: [PATCH 1218/3720] Fix compile error on MinGW Signed-off-by: Johannes Schindelin --- compat/regex/regexec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index 0194965c5d..aaf9c10cc3 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -352,7 +352,7 @@ re_search_2 (struct re_pattern_buffer *bufp, weak_alias (__re_search_2, re_search_2) #endif -static int +static int internal_function re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, @@ -396,7 +396,7 @@ re_search_2_stub (struct re_pattern_buffer *bufp, If RET_LEN is nonzero the length of the match is returned (re_match style); otherwise the position of the match is returned. */ -static int +static int internal_function re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, @@ -483,7 +483,7 @@ re_search_stub (struct re_pattern_buffer *bufp, return rval; } -static unsigned +static unsigned internal_function re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs, int regs_allocated) @@ -613,7 +613,7 @@ re_exec (s) Note: We assume front end functions already check ranges. (START + RANGE >= 0 && START + RANGE <= LENGTH) */ -static reg_errcode_t +static reg_errcode_t internal_function re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, @@ -937,7 +937,7 @@ re_search_internal (const regex_t *preg, return err; } -static reg_errcode_t +static reg_errcode_t internal_function prune_impossible_nodes (re_match_context_t *mctx) { const re_dfa_t *const dfa = mctx->dfa; From c333f507d737e639815640c5cae970b277d3a4fa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1219/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a85e2f6319..7e6cff0448 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3834,6 +3834,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From f246c59ee8609337f1dfd160e7d05f967dd3d3b7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1220/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7e6cff0448..ec0f17b463 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3849,7 +3849,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 673f3d9d4e019a15c6d3770e9f8d9b07059f16cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Mon, 6 Sep 2010 20:37:10 +1000 Subject: [PATCH 1221/3720] doc: technical details about the index file format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This bases on the original work by Robin Rosenberg. Signed-off-by: Robin Rosenberg Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- Documentation/technical/index-format.txt | 144 +++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Documentation/technical/index-format.txt diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt new file mode 100644 index 0000000000..5b1d70d1ff --- /dev/null +++ b/Documentation/technical/index-format.txt @@ -0,0 +1,144 @@ +GIT index format +================ + += The git index file has the following format + + All binary numbers are in network byte order. Version 2 is described + here unless stated otherwise. + + - A 12-byte header consisting of + + 4-byte signature: + The signature is { 'D', 'I', 'R', 'C' } + + 4-byte version number: + The current supported versions are 2 and 3. + + 32-bit number of index entries. + + - A number of sorted index entries + + - Extensions + + Extensions are identified by signature. Optional extensions can + be ignored if GIT does not understand them. + + GIT currently supports tree cache and resolve undo extensions. + + 4-byte extension signature. If the first byte is 'A'..'Z' the + extension is optional and can be ignored. + + 32-bit size of the extension + + Extension data + + - 160-bit SHA-1 over the content of the index file before this + checksum. + +== Index entry + + Index entries are sorted in ascending order on the name field, + interpreted as a string of unsigned bytes. Entries with the same + name are sorted by their stage field. + + 32-bit ctime seconds, the last time a file's metadata changed + this is stat(2) data + + 32-bit ctime nanosecond fractions + this is stat(2) data + + 32-bit mtime seconds, the last time a file's data changed + this is stat(2) data + + 32-bit mtime nanosecond fractions + this is stat(2) data + + 32-bit dev + this is stat(2) data + + 32-bit ino + this is stat(2) data + + 32-bit mode, split into (high to low bits) + + 4-bit object type + valid values in binary are 1000 (blob), 1010 (symbolic link) + and 1110 (gitlink) + + 3-bit unused + + 9-bit unix permission (only 0755 and 0644 are valid) + + 32-bit uid + this is stat(2) data + + 32-bit gid + this is stat(2) data + + 32-bit file size + This is the on-disk size from stat(2) + + 160-bit SHA-1 for the represented object + + A 16-bit field split into (high to low bits) + + 1-bit assume-valid flag + + 1-bit extended flag (must be zero in version 2) + + 2-bit stage (during merge) + + 12-bit name length if the length is less than 0x0FFF + + (Version 3) A 16-bit field, only applicable if the "extended flag" + above is 1, split into (high to low bits). + + 1-bit reserved for future + + 1-bit skip-worktree flag (used by sparse checkout) + + 1-bit intent-to-add flag (used by "git add -N") + + 13-bit unused, must be zero + + Entry path name (variable length) relative to top level directory + (without leading slash). '/' is used as path separator. The special + paths ".", ".." and ".git" (without quotes) are disallowed. + Trailing slash is also disallowed. + + The exact encoding is undefined, but the '.' and '/' characters + are encoded in 7-bit ASCII and the encoding cannot contain a nul + byte. Generally a superset of ASCII. + + 1-8 nul bytes as necessary to pad the entry to a multiple of eight bytes + while keeping the name NUL-terminated. + +== Extensions + +=== Tree cache + + Tree cache extension contains pre-computes hashes for all trees that + can be derived from the index + + - Extension tag { 'T', 'R', 'E', 'E' } + + - 32-bit size + + - A number of entries + + NUL-terminated tree name + + Blank-terminated ASCII decimal number of entries in this tree + + Newline-terminated position of this tree in the parent tree. 0 for + the root tree + + 160-bit SHA-1 for this tree and it's children + +=== Resolve undo + + TODO + + - Extension tag { 'R', 'E', 'U', 'C' } + + - 32-bit size From 5493d123ae738c5f035aab3a10ee017d18d9c5ce Mon Sep 17 00:00:00 2001 From: Nate Parsons Date: Fri, 10 Sep 2010 10:00:25 +0200 Subject: [PATCH 1222/3720] Fix compile for MinGW (continued) This fixes the fix in efe33c61(Fix compile error on MinGW). It only fixed things on one computer, but apparently not on others. The only difference between the declarations and function definitions here is the 'internal_function's. if _LIBC is not defined and __i386__ is, then this actually means something. [jes cobbled together the commit message and the commit from all over the place and cannot be held responsible for misrepresentations.] Signed-off-by: Johannes Schindelin --- compat/regex/regexec.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index aaf9c10cc3..f699b9375e 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -40,19 +40,24 @@ static reg_errcode_t re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, size_t nmatch, regmatch_t pmatch[], - int eflags); + int eflags) + internal_function; static int re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, - int stop, int ret_len); + int stop, int ret_len) + internal_function; static int re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, struct re_registers *regs, - int ret_len); + int ret_len) + internal_function; static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, - int nregs, int regs_allocated); -static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); + int nregs, int regs_allocated) + internal_function; +static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) + internal_function; static int check_matching (re_match_context_t *mctx, int fl_longest_match, int *p_match_first) internal_function; static int check_halt_state_context (const re_match_context_t *mctx, From 3772d17cbfa0e669b927629cc0fe19267753d03f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 1223/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 1f11618cfd..8415ef5234 100644 --- a/Makefile +++ b/Makefile @@ -1925,6 +1925,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1932,6 +1933,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 1fabd999ade2112d8a7b7a4b3ae7e74817ab255f Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 1224/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From c8fb69ab715a414b6a00528daf17ad17da1f2b3d Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1225/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 1e6719438f2e75a540747c3f689711da717c3315 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1226/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index dc4e83b103..a864088266 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 1e690d1240..1b354b5b51 100644 --- a/cache.h +++ b/cache.h @@ -552,6 +552,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f2d9e1fd97..9f6df8762d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index cdcf5836c6..42e94f991b 100644 --- a/config.c +++ b/config.c @@ -595,6 +595,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 83d38d3c23..ee3243c3d6 100644 --- a/environment.c +++ b/environment.c @@ -53,6 +53,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index fe845ae639..930cc5c217 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -505,4 +505,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 6927fe5001d01000e5c4c3eeb740b48bf6aa547f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1227/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 9f6df8762d..884f698873 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From b4c0ac2c68874efe184361f08e36d5664ebf2b7b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1228/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 244eba562f381e3f425796c04922f896ad2fce27 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 1229/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..1eaa83f686 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NONMINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NONMINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/test-lib.sh b/t/test-lib.sh index 29fd7209cf..be269ab2ee 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -881,6 +881,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From ae18efdd039c521345c387d0e2b95829a1cc75a6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1230/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index bb104895a9..76981e563d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1213,9 +1213,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2015,7 +2012,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2027,12 +2024,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2053,18 +2057,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2085,20 +2086,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From edb835121e13d39ef0a070988f7295dee8532f3e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1231/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 884f698873..208b9f987e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 79053a67cd2f55b5cb1552244c5d8a7cb7a9282c Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1232/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 208b9f987e..14be1bbb2e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1248,7 +1264,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 3bc5e42f19b0bb23f2dabf35c06e6322854df5b0 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1233/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 14be1bbb2e..d813203ea0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1305,6 +1358,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 5fef5d197561d8d52fde81170d0305644e3fc155 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1234/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d813203ea0..ef23b6274e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From c9603f019cd0b07540a5f866cb700bf7b7c5a663 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1235/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 76981e563d..ccbed506ad 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From f10fbb23e293391a173840df209a635ecebae70a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1236/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 1f2df883274aa53e8b7fde255985e5735cd59636 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1237/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ef23b6274e..d770c2d00c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 05a1ad95d5890414f3f21b6d4a6506aa8f996286 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1238/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d770c2d00c..12f230b665 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1590,6 +1590,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1599,9 +1600,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 8b51ab8b07266c9b29c8e1cb25c112d75458162b Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1239/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7c0a698b92..56fc26e13d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -324,4 +324,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index be269ab2ee..a64d60831d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -876,6 +876,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 14bebe7749d6ebc2ff5ae7bcee6c17762c767433 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1240/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 12f230b665..0c67afd55e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 728341d401cc60fd15bd22f74b882f8d4b88f415 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 1241/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0c67afd55e..2718b7d649 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From fba6c26f47f74b8da94bfc0609622d581cee8bec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 1242/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..6b9f76a27d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 8ad3e7d6220dc66dd9787c5ece987326c815ad98 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1243/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a72fe3ae64..2e210faf3c 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 1a300b8cae3aa28c52d1ae315dc1c18c596056b3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1244/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index a864088266..69115cdf08 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1578,6 +1578,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index d634b5a3d5..21974a0eb8 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 98f7a53008aace9862ff64b74d79fe99037caed6 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1245/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2718b7d649..62e7ba11ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 6fe9a2a8fed7fb8580e1adf903cfbab5e6fa32fd Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1246/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 6dab3bf6a7..53f89d6cd2 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1017,7 +1017,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 76b6733b54dac1bd79449d847a79ef43d880c86d Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1247/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 53f89d6cd2..e157e4b469 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1103,7 +1103,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From e1603d449ee1f2c69b66e55f828be6c80b2fddd7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1248/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 62e7ba11ce..ec26ba6655 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 501448eacad81fd4a95e99c68c43d556a6188281 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1249/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index f3d1660d02..902a9f9c21 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index ec26ba6655..c058b22654 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1731,3 +1731,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 42e94f991b..1d2410e512 100644 --- a/config.c +++ b/config.c @@ -804,7 +804,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 930cc5c217..1a123abe88 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -509,4 +509,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 6b23023095..6345b23876 100644 --- a/path.c +++ b/path.c @@ -315,7 +315,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 4e424f2a23e8ca3c865a2d4672171bcd3c099295 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1250/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index a64d60831d..10bca8574b 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -779,6 +779,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . ../GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 48195b03b8a02193adce46d71c960a8c2bbec331 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1251/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 0977f1bc831068319ae69075896421df88e7850e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1252/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From 25bf10dc5522c0cf0e8c2c297e46aec1bce5ed86 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1253/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6b9f76a27d..ae9fc2346d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 232db17ec0380d45c637affca4f351b883d82f4b Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1254/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 10bca8574b..e520cb2242 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 87f2abefafa87c2f3f9f505af6fdde1decccba48 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1255/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From f80d452e97d5f5b718bf66f34a6ac79a1871f85a Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1256/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 1b354b5b51..87cbe81f00 100644 --- a/cache.h +++ b/cache.h @@ -718,7 +718,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index c058b22654..4dc751d047 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1749,3 +1749,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 1a123abe88..72644a5132 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -179,6 +179,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 6345b23876..3870b2411a 100644 --- a/path.c +++ b/path.c @@ -730,10 +730,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 57254127d4c32191aae9a1387cfb5a0181e64c3a Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1257/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 902a9f9c21..8b5069f712 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From ceb4b10d2c12106ec33a40da283466e3be7d77ee Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1258/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4dc751d047..f96d8367b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1752,23 +1752,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From e17212ebc5e143ed6a453d215fe57efe92b98ecf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 17:40:44 +0200 Subject: [PATCH 1259/3720] Make sure that git_getpass() never returns NULL The result of git_getpass() is used without checking for NULL, so let's just die() instead of returning NULL. Signed-off-by: Johannes Schindelin --- connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 02e738a014..d3e967fcd9 100644 --- a/connect.c +++ b/connect.c @@ -628,8 +628,12 @@ char *git_getpass(const char *prompt) askpass = getenv("GIT_ASKPASS"); - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; From 9be4f117b7cebe35df74c2ef779d404f5a5e23be Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1260/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ccbed506ad..8eeebe06e2 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 72ac03529cc13b1d2ee6fd8af3a3c459d80c8734 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1261/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 25b3c58e48353c9b9c82383a87e0ebd840679031 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1262/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f96d8367b2..b0ad9192fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -701,11 +701,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From bb3656f8bfa3f1bdedc1368582b53e0c3bfefc50 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1263/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From db0493d39d4c41e222287df4c3ae201305048c71 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1264/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 25539d44ff42ad37674ea1618f1626f717e52fe6 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1265/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From edf957ba83878bca848e45672c0a141ce56db735 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1266/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From e713d484bb086d3c3da0ab2ac43be4669cd726f6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Aug 2010 12:04:40 +0200 Subject: [PATCH 1267/3720] Fix typo in pack-objects' usage Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0e81673118..3756cf36ee 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -30,7 +30,7 @@ static const char pack_usage[] = " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n" " [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n" " [--reflog] [--stdout | base-name] [--include-tag]\n" - " [--keep-unreachable | --unpack-unreachable \n" + " [--keep-unreachable | --unpack-unreachable]\n" " [ Date: Thu, 26 Aug 2010 14:34:07 +0200 Subject: [PATCH 1268/3720] Fix compile error on MinGW Signed-off-by: Johannes Schindelin --- compat/regex/regexec.c | 4369 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4369 insertions(+) create mode 100644 compat/regex/regexec.c diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c new file mode 100644 index 0000000000..aaf9c10cc3 --- /dev/null +++ b/compat/regex/regexec.c @@ -0,0 +1,4369 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2005, 2007, 2009, 2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. */ + +static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, + int n) internal_function; +static void match_ctx_clean (re_match_context_t *mctx) internal_function; +static void match_ctx_free (re_match_context_t *cache) internal_function; +static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node, + int str_idx, int from, int to) + internal_function; +static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) + internal_function; +static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node, + int str_idx) internal_function; +static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop, + int node, int str_idx) + internal_function; +static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, + re_dfastate_t **limited_sts, int last_node, + int last_str_idx) + internal_function; +static reg_errcode_t re_search_internal (const regex_t *preg, + const char *string, int length, + int start, int range, int stop, + size_t nmatch, regmatch_t pmatch[], + int eflags); +static int re_search_2_stub (struct re_pattern_buffer *bufp, + const char *string1, int length1, + const char *string2, int length2, + int start, int range, struct re_registers *regs, + int stop, int ret_len); +static int re_search_stub (struct re_pattern_buffer *bufp, + const char *string, int length, int start, + int range, int stop, struct re_registers *regs, + int ret_len); +static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, + int nregs, int regs_allocated); +static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); +static int check_matching (re_match_context_t *mctx, int fl_longest_match, + int *p_match_first) internal_function; +static int check_halt_state_context (const re_match_context_t *mctx, + const re_dfastate_t *state, int idx) + internal_function; +static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, int cur_node, + int cur_idx, int nmatch) internal_function; +static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, + int str_idx, int dest_node, int nregs, + regmatch_t *regs, + re_node_set *eps_via_nodes) + internal_function; +static reg_errcode_t set_regs (const regex_t *preg, + const re_match_context_t *mctx, + size_t nmatch, regmatch_t *pmatch, + int fl_backtrack) internal_function; +static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) + internal_function; + +#ifdef RE_ENABLE_I18N +static int sift_states_iter_mb (const re_match_context_t *mctx, + re_sift_context_t *sctx, + int node_idx, int str_idx, int max_str_idx) + internal_function; +#endif /* RE_ENABLE_I18N */ +static reg_errcode_t sift_states_backward (const re_match_context_t *mctx, + re_sift_context_t *sctx) + internal_function; +static reg_errcode_t build_sifted_states (const re_match_context_t *mctx, + re_sift_context_t *sctx, int str_idx, + re_node_set *cur_dest) + internal_function; +static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx, + re_sift_context_t *sctx, + int str_idx, + re_node_set *dest_nodes) + internal_function; +static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa, + re_node_set *dest_nodes, + const re_node_set *candidates) + internal_function; +static int check_dst_limits (const re_match_context_t *mctx, + re_node_set *limits, + int dst_node, int dst_idx, int src_node, + int src_idx) internal_function; +static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, + int boundaries, int subexp_idx, + int from_node, int bkref_idx) + internal_function; +static int check_dst_limits_calc_pos (const re_match_context_t *mctx, + int limit, int subexp_idx, + int node, int str_idx, + int bkref_idx) internal_function; +static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa, + re_node_set *dest_nodes, + const re_node_set *candidates, + re_node_set *limits, + struct re_backref_cache_entry *bkref_ents, + int str_idx) internal_function; +static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx, + re_sift_context_t *sctx, + int str_idx, const re_node_set *candidates) + internal_function; +static reg_errcode_t merge_state_array (const re_dfa_t *dfa, + re_dfastate_t **dst, + re_dfastate_t **src, int num) + internal_function; +static re_dfastate_t *find_recover_state (reg_errcode_t *err, + re_match_context_t *mctx) internal_function; +static re_dfastate_t *transit_state (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *state) internal_function; +static re_dfastate_t *merge_state_with_log (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *next_state) + internal_function; +static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx, + re_node_set *cur_nodes, + int str_idx) internal_function; +#if 0 +static re_dfastate_t *transit_state_sb (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *pstate) + internal_function; +#endif +#ifdef RE_ENABLE_I18N +static reg_errcode_t transit_state_mb (re_match_context_t *mctx, + re_dfastate_t *pstate) + internal_function; +#endif /* RE_ENABLE_I18N */ +static reg_errcode_t transit_state_bkref (re_match_context_t *mctx, + const re_node_set *nodes) + internal_function; +static reg_errcode_t get_subexp (re_match_context_t *mctx, + int bkref_node, int bkref_str_idx) + internal_function; +static reg_errcode_t get_subexp_sub (re_match_context_t *mctx, + const re_sub_match_top_t *sub_top, + re_sub_match_last_t *sub_last, + int bkref_node, int bkref_str) + internal_function; +static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, + int subexp_idx, int type) internal_function; +static reg_errcode_t check_arrival (re_match_context_t *mctx, + state_array_t *path, int top_node, + int top_str, int last_node, int last_str, + int type) internal_function; +static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx, + int str_idx, + re_node_set *cur_nodes, + re_node_set *next_nodes) + internal_function; +static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa, + re_node_set *cur_nodes, + int ex_subexp, int type) + internal_function; +static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa, + re_node_set *dst_nodes, + int target, int ex_subexp, + int type) internal_function; +static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx, + re_node_set *cur_nodes, int cur_str, + int subexp_num, int type) + internal_function; +static int build_trtable (const re_dfa_t *dfa, + re_dfastate_t *state) internal_function; +#ifdef RE_ENABLE_I18N +static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, + const re_string_t *input, int idx) + internal_function; +# ifdef _LIBC +static unsigned int find_collation_sequence_value (const unsigned char *mbs, + size_t name_len) + internal_function; +# endif /* _LIBC */ +#endif /* RE_ENABLE_I18N */ +static int group_nodes_into_DFAstates (const re_dfa_t *dfa, + const re_dfastate_t *state, + re_node_set *states_node, + bitset_t *states_ch) internal_function; +static int check_node_accept (const re_match_context_t *mctx, + const re_token_t *node, int idx) + internal_function; +static reg_errcode_t extend_buffers (re_match_context_t *mctx) + internal_function; + +/* Entry point for POSIX code. */ + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec ( + const regex_t *__restrict preg, + const char *__restrict string, + size_t nmatch, + regmatch_t pmatch[], + int eflags) +{ + reg_errcode_t err; + int start, length; + + if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) + return REG_BADPAT; + + if (eflags & REG_STARTEND) + { + start = pmatch[0].rm_so; + length = pmatch[0].rm_eo; + } + else + { + start = 0; + length = strlen (string); + } + + __libc_lock_lock (dfa->lock); + if (preg->no_sub) + err = re_search_internal (preg, string, length, start, length - start, + length, 0, NULL, eflags); + else + err = re_search_internal (preg, string, length, start, length - start, + length, nmatch, pmatch, eflags); + __libc_lock_unlock (dfa->lock); + return err != REG_NOERROR; +} + +#ifdef _LIBC +# include +versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4); + +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) +__typeof__ (__regexec) __compat_regexec; + +int +attribute_compat_text_section +__compat_regexec (const regex_t *__restrict preg, + const char *__restrict string, size_t nmatch, + regmatch_t pmatch[], int eflags) +{ + return regexec (preg, string, nmatch, pmatch, + eflags & (REG_NOTBOL | REG_NOTEOL)); +} +compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); +# endif +#endif + +/* Entry points for GNU code. */ + +/* re_match, re_search, re_match_2, re_search_2 + + The former two functions operate on STRING with length LENGTH, + while the later two operate on concatenation of STRING1 and STRING2 + with lengths LENGTH1 and LENGTH2, respectively. + + re_match() matches the compiled pattern in BUFP against the string, + starting at index START. + + re_search() first tries matching at index START, then it tries to match + starting from index START + 1, and so on. The last start position tried + is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same + way as re_match().) + + The parameter STOP of re_{match,search}_2 specifies that no match exceeding + the first STOP characters of the concatenation of the strings should be + concerned. + + If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match + and all groups is stroed in REGS. (For the "_2" variants, the offsets are + computed relative to the concatenation, not relative to the individual + strings.) + + On success, re_match* functions return the length of the match, re_search* + return the position of the start of the match. Return value -1 means no + match was found and -2 indicates an internal error. */ + +int +re_match (struct re_pattern_buffer *bufp, + const char *string, + int length, + int start, + struct re_registers *regs) +{ + return re_search_stub (bufp, string, length, start, 0, length, regs, 1); +} +#ifdef _LIBC +weak_alias (__re_match, re_match) +#endif + +int +re_search (struct re_pattern_buffer *bufp, + const char *string, + int length, int start, int range, + struct re_registers *regs) +{ + return re_search_stub (bufp, string, length, start, range, length, regs, 0); +} +#ifdef _LIBC +weak_alias (__re_search, re_search) +#endif + +int +re_match_2 (struct re_pattern_buffer *bufp, + const char *string1, int length1, + const char *string2, int length2, int start, + struct re_registers *regs, int stop) +{ + return re_search_2_stub (bufp, string1, length1, string2, length2, + start, 0, regs, stop, 1); +} +#ifdef _LIBC +weak_alias (__re_match_2, re_match_2) +#endif + +int +re_search_2 (struct re_pattern_buffer *bufp, + const char *string1, int length1, + const char *string2, int length2, int start, + int range, struct re_registers *regs, int stop) +{ + return re_search_2_stub (bufp, string1, length1, string2, length2, + start, range, regs, stop, 0); +} +#ifdef _LIBC +weak_alias (__re_search_2, re_search_2) +#endif + +static int internal_function +re_search_2_stub (struct re_pattern_buffer *bufp, + const char *string1, int length1, + const char *string2, int length2, int start, + int range, struct re_registers *regs, + int stop, int ret_len) +{ + const char *str; + int rval; + int len = length1 + length2; + int free_str = 0; + + if (BE (length1 < 0 || length2 < 0 || stop < 0, 0)) + return -2; + + /* Concatenate the strings. */ + if (length2 > 0) + if (length1 > 0) + { + char *s = re_malloc (char, len); + + if (BE (s == NULL, 0)) + return -2; + memcpy (s, string1, length1); + memcpy (s + length1, string2, length2); + str = s; + free_str = 1; + } + else + str = string2; + else + str = string1; + + rval = re_search_stub (bufp, str, len, start, range, stop, regs, ret_len); + if (free_str) + re_free ((char *) str); + return rval; +} + +/* The parameters have the same meaning as those of re_search. + Additional parameters: + If RET_LEN is nonzero the length of the match is returned (re_match style); + otherwise the position of the match is returned. */ + +static int internal_function +re_search_stub (struct re_pattern_buffer *bufp, + const char *string, int length, int start, + int range, int stop, + struct re_registers *regs, int ret_len) +{ + reg_errcode_t result; + regmatch_t *pmatch; + int nregs, rval; + int eflags = 0; + + /* Check for out-of-range. */ + if (BE (start < 0 || start > length, 0)) + return -1; + if (BE (start + range > length, 0)) + range = length - start; + else if (BE (start + range < 0, 0)) + range = -start; + + __libc_lock_lock (dfa->lock); + + eflags |= (bufp->not_bol) ? REG_NOTBOL : 0; + eflags |= (bufp->not_eol) ? REG_NOTEOL : 0; + + /* Compile fastmap if we haven't yet. */ + if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate) + re_compile_fastmap (bufp); + + if (BE (bufp->no_sub, 0)) + regs = NULL; + + /* We need at least 1 register. */ + if (regs == NULL) + nregs = 1; + else if (BE (bufp->regs_allocated == REGS_FIXED && + regs->num_regs < bufp->re_nsub + 1, 0)) + { + nregs = regs->num_regs; + if (BE (nregs < 1, 0)) + { + /* Nothing can be copied to regs. */ + regs = NULL; + nregs = 1; + } + } + else + nregs = bufp->re_nsub + 1; + pmatch = re_malloc (regmatch_t, nregs); + if (BE (pmatch == NULL, 0)) + { + rval = -2; + goto out; + } + + result = re_search_internal (bufp, string, length, start, range, stop, + nregs, pmatch, eflags); + + rval = 0; + + /* I hope we needn't fill ther regs with -1's when no match was found. */ + if (result != REG_NOERROR) + rval = -1; + else if (regs != NULL) + { + /* If caller wants register contents data back, copy them. */ + bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs, + bufp->regs_allocated); + if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0)) + rval = -2; + } + + if (BE (rval == 0, 1)) + { + if (ret_len) + { + assert (pmatch[0].rm_so == start); + rval = pmatch[0].rm_eo - start; + } + else + rval = pmatch[0].rm_so; + } + re_free (pmatch); + out: + __libc_lock_unlock (dfa->lock); + return rval; +} + +static unsigned internal_function +re_copy_regs (struct re_registers *regs, + regmatch_t *pmatch, + int nregs, int regs_allocated) +{ + int rval = REGS_REALLOCATE; + int i; + int need_regs = nregs + 1; + /* We need one extra element beyond `num_regs' for the `-1' marker GNU code + uses. */ + + /* Have the register data arrays been allocated? */ + if (regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. */ + regs->start = re_malloc (regoff_t, need_regs); + if (BE (regs->start == NULL, 0)) + return REGS_UNALLOCATED; + regs->end = re_malloc (regoff_t, need_regs); + if (BE (regs->end == NULL, 0)) + { + re_free (regs->start); + return REGS_UNALLOCATED; + } + regs->num_regs = need_regs; + } + else if (regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (BE (need_regs > regs->num_regs, 0)) + { + regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs); + regoff_t *new_end; + if (BE (new_start == NULL, 0)) + return REGS_UNALLOCATED; + new_end = re_realloc (regs->end, regoff_t, need_regs); + if (BE (new_end == NULL, 0)) + { + re_free (new_start); + return REGS_UNALLOCATED; + } + regs->start = new_start; + regs->end = new_end; + regs->num_regs = need_regs; + } + } + else + { + assert (regs_allocated == REGS_FIXED); + /* This function may not be called with REGS_FIXED and nregs too big. */ + assert (regs->num_regs >= nregs); + rval = REGS_FIXED; + } + + /* Copy the regs. */ + for (i = 0; i < nregs; ++i) + { + regs->start[i] = pmatch[i].rm_so; + regs->end[i] = pmatch[i].rm_eo; + } + for ( ; i < regs->num_regs; ++i) + regs->start[i] = regs->end[i] = -1; + + return rval; +} + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (struct re_pattern_buffer *bufp, + struct re_registers *regs, + unsigned num_regs, + regoff_t *starts, + regoff_t *ends) +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t *) 0; + } +} +#ifdef _LIBC +weak_alias (__re_set_registers, re_set_registers) +#endif + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC +int +# ifdef _LIBC +weak_function +# endif +re_exec (s) + const char *s; +{ + return 0 == regexec (&re_comp_buf, s, 0, NULL, 0); +} +#endif /* _REGEX_RE_COMP */ + +/* Internal entry point. */ + +/* Searches for a compiled pattern PREG in the string STRING, whose + length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same + mingings with regexec. START, and RANGE have the same meanings + with re_search. + Return REG_NOERROR if we find a match, and REG_NOMATCH if not, + otherwise return the error code. + Note: We assume front end functions already check ranges. + (START + RANGE >= 0 && START + RANGE <= LENGTH) */ + +static reg_errcode_t internal_function +re_search_internal (const regex_t *preg, + const char *string, + int length, int start, int range, int stop, + size_t nmatch, regmatch_t pmatch[], + int eflags) +{ + reg_errcode_t err; + const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; + int left_lim, right_lim, incr; + int fl_longest_match, match_first, match_kind, match_last = -1; + int extra_nmatch; + int sb, ch; +#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) + re_match_context_t mctx = { .dfa = dfa }; +#else + re_match_context_t mctx; +#endif + char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate + && range && !preg->can_be_null) ? preg->fastmap : NULL; + RE_TRANSLATE_TYPE t = preg->translate; + +#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) + memset (&mctx, '\0', sizeof (re_match_context_t)); + mctx.dfa = dfa; +#endif + + extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; + nmatch -= extra_nmatch; + + /* Check if the DFA haven't been compiled. */ + if (BE (preg->used == 0 || dfa->init_state == NULL + || dfa->init_state_word == NULL || dfa->init_state_nl == NULL + || dfa->init_state_begbuf == NULL, 0)) + return REG_NOMATCH; + +#ifdef DEBUG + /* We assume front-end functions already check them. */ + assert (start + range >= 0 && start + range <= length); +#endif + + /* If initial states with non-begbuf contexts have no elements, + the regex must be anchored. If preg->newline_anchor is set, + we'll never use init_state_nl, so do not check it. */ + if (dfa->init_state->nodes.nelem == 0 + && dfa->init_state_word->nodes.nelem == 0 + && (dfa->init_state_nl->nodes.nelem == 0 + || !preg->newline_anchor)) + { + if (start != 0 && start + range != 0) + return REG_NOMATCH; + start = range = 0; + } + + /* We must check the longest matching, if nmatch > 0. */ + fl_longest_match = (nmatch != 0 || dfa->nbackref); + + err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1, + preg->translate, preg->syntax & RE_ICASE, dfa); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + mctx.input.stop = stop; + mctx.input.raw_stop = stop; + mctx.input.newline_anchor = preg->newline_anchor; + + err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + + /* We will log all the DFA states through which the dfa pass, + if nmatch > 1, or this dfa has "multibyte node", which is a + back-reference or a node which can accept multibyte character or + multi character collating element. */ + if (nmatch > 1 || dfa->has_mb_node) + { + /* Avoid overflow. */ + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= mctx.input.bufs_len, 0)) + { + err = REG_ESPACE; + goto free_return; + } + + mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1); + if (BE (mctx.state_log == NULL, 0)) + { + err = REG_ESPACE; + goto free_return; + } + } + else + mctx.state_log = NULL; + + match_first = start; + mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF + : CONTEXT_NEWLINE | CONTEXT_BEGBUF; + + /* Check incrementally whether of not the input string match. */ + incr = (range < 0) ? -1 : 1; + left_lim = (range < 0) ? start + range : start; + right_lim = (range < 0) ? start : start + range; + sb = dfa->mb_cur_max == 1; + match_kind = + (fastmap + ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) + | (range >= 0 ? 2 : 0) + | (t != NULL ? 1 : 0)) + : 8); + + for (;; match_first += incr) + { + err = REG_NOMATCH; + if (match_first < left_lim || right_lim < match_first) + goto free_return; + + /* Advance as rapidly as possible through the string, until we + find a plausible place to start matching. This may be done + with varying efficiency, so there are various possibilities: + only the most common of them are specialized, in order to + save on code size. We use a switch statement for speed. */ + switch (match_kind) + { + case 8: + /* No fastmap. */ + break; + + case 7: + /* Fastmap with single-byte translation, match forward. */ + while (BE (match_first < right_lim, 1) + && !fastmap[t[(unsigned char) string[match_first]]]) + ++match_first; + goto forward_match_found_start_or_reached_end; + + case 6: + /* Fastmap without translation, match forward. */ + while (BE (match_first < right_lim, 1) + && !fastmap[(unsigned char) string[match_first]]) + ++match_first; + + forward_match_found_start_or_reached_end: + if (BE (match_first == right_lim, 0)) + { + ch = match_first >= length + ? 0 : (unsigned char) string[match_first]; + if (!fastmap[t ? t[ch] : ch]) + goto free_return; + } + break; + + case 4: + case 5: + /* Fastmap without multi-byte translation, match backwards. */ + while (match_first >= left_lim) + { + ch = match_first >= length + ? 0 : (unsigned char) string[match_first]; + if (fastmap[t ? t[ch] : ch]) + break; + --match_first; + } + if (match_first < left_lim) + goto free_return; + break; + + default: + /* In this case, we can't determine easily the current byte, + since it might be a component byte of a multibyte + character. Then we use the constructed buffer instead. */ + for (;;) + { + /* If MATCH_FIRST is out of the valid range, reconstruct the + buffers. */ + unsigned int offset = match_first - mctx.input.raw_mbs_idx; + if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0)) + { + err = re_string_reconstruct (&mctx.input, match_first, + eflags); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + + offset = match_first - mctx.input.raw_mbs_idx; + } + /* If MATCH_FIRST is out of the buffer, leave it as '\0'. + Note that MATCH_FIRST must not be smaller than 0. */ + ch = (match_first >= length + ? 0 : re_string_byte_at (&mctx.input, offset)); + if (fastmap[ch]) + break; + match_first += incr; + if (match_first < left_lim || match_first > right_lim) + { + err = REG_NOMATCH; + goto free_return; + } + } + break; + } + + /* Reconstruct the buffers so that the matcher can assume that + the matching starts from the beginning of the buffer. */ + err = re_string_reconstruct (&mctx.input, match_first, eflags); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + +#ifdef RE_ENABLE_I18N + /* Don't consider this char as a possible match start if it part, + yet isn't the head, of a multibyte character. */ + if (!sb && !re_string_first_byte (&mctx.input, 0)) + continue; +#endif + + /* It seems to be appropriate one, then use the matcher. */ + /* We assume that the matching starts from 0. */ + mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; + match_last = check_matching (&mctx, fl_longest_match, + range >= 0 ? &match_first : NULL); + if (match_last != -1) + { + if (BE (match_last == -2, 0)) + { + err = REG_ESPACE; + goto free_return; + } + else + { + mctx.match_last = match_last; + if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) + { + re_dfastate_t *pstate = mctx.state_log[match_last]; + mctx.last_node = check_halt_state_context (&mctx, pstate, + match_last); + } + if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) + || dfa->nbackref) + { + err = prune_impossible_nodes (&mctx); + if (err == REG_NOERROR) + break; + if (BE (err != REG_NOMATCH, 0)) + goto free_return; + match_last = -1; + } + else + break; /* We found a match. */ + } + } + + match_ctx_clean (&mctx); + } + +#ifdef DEBUG + assert (match_last != -1); + assert (err == REG_NOERROR); +#endif + + /* Set pmatch[] if we need. */ + if (nmatch > 0) + { + int reg_idx; + + /* Initialize registers. */ + for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) + pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; + + /* Set the points where matching start/end. */ + pmatch[0].rm_so = 0; + pmatch[0].rm_eo = mctx.match_last; + + if (!preg->no_sub && nmatch > 1) + { + err = set_regs (preg, &mctx, nmatch, pmatch, + dfa->has_plural_match && dfa->nbackref > 0); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + + /* At last, add the offset to the each registers, since we slided + the buffers so that we could assume that the matching starts + from 0. */ + for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) + if (pmatch[reg_idx].rm_so != -1) + { +#ifdef RE_ENABLE_I18N + if (BE (mctx.input.offsets_needed != 0, 0)) + { + pmatch[reg_idx].rm_so = + (pmatch[reg_idx].rm_so == mctx.input.valid_len + ? mctx.input.valid_raw_len + : mctx.input.offsets[pmatch[reg_idx].rm_so]); + pmatch[reg_idx].rm_eo = + (pmatch[reg_idx].rm_eo == mctx.input.valid_len + ? mctx.input.valid_raw_len + : mctx.input.offsets[pmatch[reg_idx].rm_eo]); + } +#else + assert (mctx.input.offsets_needed == 0); +#endif + pmatch[reg_idx].rm_so += match_first; + pmatch[reg_idx].rm_eo += match_first; + } + for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) + { + pmatch[nmatch + reg_idx].rm_so = -1; + pmatch[nmatch + reg_idx].rm_eo = -1; + } + + if (dfa->subexp_map) + for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) + if (dfa->subexp_map[reg_idx] != reg_idx) + { + pmatch[reg_idx + 1].rm_so + = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; + pmatch[reg_idx + 1].rm_eo + = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo; + } + } + + free_return: + re_free (mctx.state_log); + if (dfa->nbackref) + match_ctx_free (&mctx); + re_string_destruct (&mctx.input); + return err; +} + +static reg_errcode_t internal_function +prune_impossible_nodes (re_match_context_t *mctx) +{ + const re_dfa_t *const dfa = mctx->dfa; + int halt_node, match_last; + reg_errcode_t ret; + re_dfastate_t **sifted_states; + re_dfastate_t **lim_states = NULL; + re_sift_context_t sctx; +#ifdef DEBUG + assert (mctx->state_log != NULL); +#endif + match_last = mctx->match_last; + halt_node = mctx->last_node; + + /* Avoid overflow. */ + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= match_last, 0)) + return REG_ESPACE; + + sifted_states = re_malloc (re_dfastate_t *, match_last + 1); + if (BE (sifted_states == NULL, 0)) + { + ret = REG_ESPACE; + goto free_return; + } + if (dfa->nbackref) + { + lim_states = re_malloc (re_dfastate_t *, match_last + 1); + if (BE (lim_states == NULL, 0)) + { + ret = REG_ESPACE; + goto free_return; + } + while (1) + { + memset (lim_states, '\0', + sizeof (re_dfastate_t *) * (match_last + 1)); + sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, + match_last); + ret = sift_states_backward (mctx, &sctx); + re_node_set_free (&sctx.limits); + if (BE (ret != REG_NOERROR, 0)) + goto free_return; + if (sifted_states[0] != NULL || lim_states[0] != NULL) + break; + do + { + --match_last; + if (match_last < 0) + { + ret = REG_NOMATCH; + goto free_return; + } + } while (mctx->state_log[match_last] == NULL + || !mctx->state_log[match_last]->halt); + halt_node = check_halt_state_context (mctx, + mctx->state_log[match_last], + match_last); + } + ret = merge_state_array (dfa, sifted_states, lim_states, + match_last + 1); + re_free (lim_states); + lim_states = NULL; + if (BE (ret != REG_NOERROR, 0)) + goto free_return; + } + else + { + sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last); + ret = sift_states_backward (mctx, &sctx); + re_node_set_free (&sctx.limits); + if (BE (ret != REG_NOERROR, 0)) + goto free_return; + if (sifted_states[0] == NULL) + { + ret = REG_NOMATCH; + goto free_return; + } + } + re_free (mctx->state_log); + mctx->state_log = sifted_states; + sifted_states = NULL; + mctx->last_node = halt_node; + mctx->match_last = match_last; + ret = REG_NOERROR; + free_return: + re_free (sifted_states); + re_free (lim_states); + return ret; +} + +/* Acquire an initial state and return it. + We must select appropriate initial state depending on the context, + since initial states may have constraints like "\<", "^", etc.. */ + +static inline re_dfastate_t * +__attribute ((always_inline)) internal_function +acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx, + int idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + if (dfa->init_state->has_constraint) + { + unsigned int context; + context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags); + if (IS_WORD_CONTEXT (context)) + return dfa->init_state_word; + else if (IS_ORDINARY_CONTEXT (context)) + return dfa->init_state; + else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context)) + return dfa->init_state_begbuf; + else if (IS_NEWLINE_CONTEXT (context)) + return dfa->init_state_nl; + else if (IS_BEGBUF_CONTEXT (context)) + { + /* It is relatively rare case, then calculate on demand. */ + return re_acquire_state_context (err, dfa, + dfa->init_state->entrance_nodes, + context); + } + else + /* Must not happen? */ + return dfa->init_state; + } + else + return dfa->init_state; +} + +/* Check whether the regular expression match input string INPUT or not, + and return the index where the matching end, return -1 if not match, + or return -2 in case of an error. + FL_LONGEST_MATCH means we want the POSIX longest matching. + If P_MATCH_FIRST is not NULL, and the match fails, it is set to the + next place where we may want to try matching. + Note that the matcher assume that the maching starts from the current + index of the buffer. */ + +static int +internal_function +check_matching (re_match_context_t *mctx, int fl_longest_match, + int *p_match_first) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + int match = 0; + int match_last = -1; + int cur_str_idx = re_string_cur_idx (&mctx->input); + re_dfastate_t *cur_state; + int at_init_state = p_match_first != NULL; + int next_start_idx = cur_str_idx; + + err = REG_NOERROR; + cur_state = acquire_init_state_context (&err, mctx, cur_str_idx); + /* An initial state must not be NULL (invalid). */ + if (BE (cur_state == NULL, 0)) + { + assert (err == REG_ESPACE); + return -2; + } + + if (mctx->state_log != NULL) + { + mctx->state_log[cur_str_idx] = cur_state; + + /* Check OP_OPEN_SUBEXP in the initial state in case that we use them + later. E.g. Processing back references. */ + if (BE (dfa->nbackref, 0)) + { + at_init_state = 0; + err = check_subexp_matching_top (mctx, &cur_state->nodes, 0); + if (BE (err != REG_NOERROR, 0)) + return err; + + if (cur_state->has_backref) + { + err = transit_state_bkref (mctx, &cur_state->nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + } + + /* If the RE accepts NULL string. */ + if (BE (cur_state->halt, 0)) + { + if (!cur_state->has_constraint + || check_halt_state_context (mctx, cur_state, cur_str_idx)) + { + if (!fl_longest_match) + return cur_str_idx; + else + { + match_last = cur_str_idx; + match = 1; + } + } + } + + while (!re_string_eoi (&mctx->input)) + { + re_dfastate_t *old_state = cur_state; + int next_char_idx = re_string_cur_idx (&mctx->input) + 1; + + if (BE (next_char_idx >= mctx->input.bufs_len, 0) + || (BE (next_char_idx >= mctx->input.valid_len, 0) + && mctx->input.valid_len < mctx->input.len)) + { + err = extend_buffers (mctx); + if (BE (err != REG_NOERROR, 0)) + { + assert (err == REG_ESPACE); + return -2; + } + } + + cur_state = transit_state (&err, mctx, cur_state); + if (mctx->state_log != NULL) + cur_state = merge_state_with_log (&err, mctx, cur_state); + + if (cur_state == NULL) + { + /* Reached the invalid state or an error. Try to recover a valid + state using the state log, if available and if we have not + already found a valid (even if not the longest) match. */ + if (BE (err != REG_NOERROR, 0)) + return -2; + + if (mctx->state_log == NULL + || (match && !fl_longest_match) + || (cur_state = find_recover_state (&err, mctx)) == NULL) + break; + } + + if (BE (at_init_state, 0)) + { + if (old_state == cur_state) + next_start_idx = next_char_idx; + else + at_init_state = 0; + } + + if (cur_state->halt) + { + /* Reached a halt state. + Check the halt state can satisfy the current context. */ + if (!cur_state->has_constraint + || check_halt_state_context (mctx, cur_state, + re_string_cur_idx (&mctx->input))) + { + /* We found an appropriate halt state. */ + match_last = re_string_cur_idx (&mctx->input); + match = 1; + + /* We found a match, do not modify match_first below. */ + p_match_first = NULL; + if (!fl_longest_match) + break; + } + } + } + + if (p_match_first) + *p_match_first += next_start_idx; + + return match_last; +} + +/* Check NODE match the current context. */ + +static int +internal_function +check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context) +{ + re_token_type_t type = dfa->nodes[node].type; + unsigned int constraint = dfa->nodes[node].constraint; + if (type != END_OF_RE) + return 0; + if (!constraint) + return 1; + if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context)) + return 0; + return 1; +} + +/* Check the halt state STATE match the current context. + Return 0 if not match, if the node, STATE has, is a halt node and + match the context, return the node. */ + +static int +internal_function +check_halt_state_context (const re_match_context_t *mctx, + const re_dfastate_t *state, int idx) +{ + int i; + unsigned int context; +#ifdef DEBUG + assert (state->halt); +#endif + context = re_string_context_at (&mctx->input, idx, mctx->eflags); + for (i = 0; i < state->nodes.nelem; ++i) + if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context)) + return state->nodes.elems[i]; + return 0; +} + +/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA + corresponding to the DFA). + Return the destination node, and update EPS_VIA_NODES, return -1 in case + of errors. */ + +static int +internal_function +proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs, + int *pidx, int node, re_node_set *eps_via_nodes, + struct re_fail_stack_t *fs) +{ + const re_dfa_t *const dfa = mctx->dfa; + int i, err; + if (IS_EPSILON_NODE (dfa->nodes[node].type)) + { + re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; + re_node_set *edests = &dfa->edests[node]; + int dest_node; + err = re_node_set_insert (eps_via_nodes, node); + if (BE (err < 0, 0)) + return -2; + /* Pick up a valid destination, or return -1 if none is found. */ + for (dest_node = -1, i = 0; i < edests->nelem; ++i) + { + int candidate = edests->elems[i]; + if (!re_node_set_contains (cur_nodes, candidate)) + continue; + if (dest_node == -1) + dest_node = candidate; + + else + { + /* In order to avoid infinite loop like "(a*)*", return the second + epsilon-transition if the first was already considered. */ + if (re_node_set_contains (eps_via_nodes, dest_node)) + return candidate; + + /* Otherwise, push the second epsilon-transition on the fail stack. */ + else if (fs != NULL + && push_fail_stack (fs, *pidx, candidate, nregs, regs, + eps_via_nodes)) + return -2; + + /* We know we are going to exit. */ + break; + } + } + return dest_node; + } + else + { + int naccepted = 0; + re_token_type_t type = dfa->nodes[node].type; + +#ifdef RE_ENABLE_I18N + if (dfa->nodes[node].accept_mb) + naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx); + else +#endif /* RE_ENABLE_I18N */ + if (type == OP_BACK_REF) + { + int subexp_idx = dfa->nodes[node].opr.idx + 1; + naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; + if (fs != NULL) + { + if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) + return -1; + else if (naccepted) + { + char *buf = (char *) re_string_get_buffer (&mctx->input); + if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, + naccepted) != 0) + return -1; + } + } + + if (naccepted == 0) + { + int dest_node; + err = re_node_set_insert (eps_via_nodes, node); + if (BE (err < 0, 0)) + return -2; + dest_node = dfa->edests[node].elems[0]; + if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, + dest_node)) + return dest_node; + } + } + + if (naccepted != 0 + || check_node_accept (mctx, dfa->nodes + node, *pidx)) + { + int dest_node = dfa->nexts[node]; + *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; + if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL + || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, + dest_node))) + return -1; + re_node_set_empty (eps_via_nodes); + return dest_node; + } + } + return -1; +} + +static reg_errcode_t +internal_function +push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node, + int nregs, regmatch_t *regs, re_node_set *eps_via_nodes) +{ + reg_errcode_t err; + int num = fs->num++; + if (fs->num == fs->alloc) + { + struct re_fail_stack_ent_t *new_array; + new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t) + * fs->alloc * 2)); + if (new_array == NULL) + return REG_ESPACE; + fs->alloc *= 2; + fs->stack = new_array; + } + fs->stack[num].idx = str_idx; + fs->stack[num].node = dest_node; + fs->stack[num].regs = re_malloc (regmatch_t, nregs); + if (fs->stack[num].regs == NULL) + return REG_ESPACE; + memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); + err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); + return err; +} + +static int +internal_function +pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs, + regmatch_t *regs, re_node_set *eps_via_nodes) +{ + int num = --fs->num; + assert (num >= 0); + *pidx = fs->stack[num].idx; + memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); + re_node_set_free (eps_via_nodes); + re_free (fs->stack[num].regs); + *eps_via_nodes = fs->stack[num].eps_via_nodes; + return fs->stack[num].node; +} + +/* Set the positions where the subexpressions are starts/ends to registers + PMATCH. + Note: We assume that pmatch[0] is already set, and + pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ + +static reg_errcode_t +internal_function +set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, + regmatch_t *pmatch, int fl_backtrack) +{ + const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; + int idx, cur_node; + re_node_set eps_via_nodes; + struct re_fail_stack_t *fs; + struct re_fail_stack_t fs_body = { 0, 2, NULL }; + regmatch_t *prev_idx_match; + int prev_idx_match_malloced = 0; + +#ifdef DEBUG + assert (nmatch > 1); + assert (mctx->state_log != NULL); +#endif + if (fl_backtrack) + { + fs = &fs_body; + fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); + if (fs->stack == NULL) + return REG_ESPACE; + } + else + fs = NULL; + + cur_node = dfa->init_node; + re_node_set_init_empty (&eps_via_nodes); + +#ifdef HAVE_ALLOCA + if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) + prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); + else +#endif + { + prev_idx_match = re_malloc (regmatch_t, nmatch); + if (prev_idx_match == NULL) + { + free_fail_stack_return (fs); + return REG_ESPACE; + } + prev_idx_match_malloced = 1; + } + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); + + for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) + { + update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); + + if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) + { + int reg_idx; + if (fs) + { + for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) + if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) + break; + if (reg_idx == nmatch) + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return free_fail_stack_return (fs); + } + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + &eps_via_nodes); + } + else + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return REG_NOERROR; + } + } + + /* Proceed to next node. */ + cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, + &eps_via_nodes, fs); + + if (BE (cur_node < 0, 0)) + { + if (BE (cur_node == -2, 0)) + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + free_fail_stack_return (fs); + return REG_ESPACE; + } + if (fs) + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + &eps_via_nodes); + else + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return REG_NOMATCH; + } + } + } + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return free_fail_stack_return (fs); +} + +static reg_errcode_t +internal_function +free_fail_stack_return (struct re_fail_stack_t *fs) +{ + if (fs) + { + int fs_idx; + for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) + { + re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); + re_free (fs->stack[fs_idx].regs); + } + re_free (fs->stack); + } + return REG_NOERROR; +} + +static void +internal_function +update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch) +{ + int type = dfa->nodes[cur_node].type; + if (type == OP_OPEN_SUBEXP) + { + int reg_num = dfa->nodes[cur_node].opr.idx + 1; + + /* We are at the first node of this sub expression. */ + if (reg_num < nmatch) + { + pmatch[reg_num].rm_so = cur_idx; + pmatch[reg_num].rm_eo = -1; + } + } + else if (type == OP_CLOSE_SUBEXP) + { + int reg_num = dfa->nodes[cur_node].opr.idx + 1; + if (reg_num < nmatch) + { + /* We are at the last node of this sub expression. */ + if (pmatch[reg_num].rm_so < cur_idx) + { + pmatch[reg_num].rm_eo = cur_idx; + /* This is a non-empty match or we are not inside an optional + subexpression. Accept this right away. */ + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); + } + else + { + if (dfa->nodes[cur_node].opt_subexp + && prev_idx_match[reg_num].rm_so != -1) + /* We transited through an empty match for an optional + subexpression, like (a?)*, and this is not the subexp's + first match. Copy back the old content of the registers + so that matches of an inner subexpression are undone as + well, like in ((a?))*. */ + memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); + else + /* We completed a subexpression, but it may be part of + an optional one, so do not update PREV_IDX_MATCH. */ + pmatch[reg_num].rm_eo = cur_idx; + } + } + } +} + +/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 + and sift the nodes in each states according to the following rules. + Updated state_log will be wrote to STATE_LOG. + + Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if... + 1. When STR_IDX == MATCH_LAST(the last index in the state_log): + If `a' isn't the LAST_NODE and `a' can't epsilon transit to + the LAST_NODE, we throw away the node `a'. + 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts + string `s' and transit to `b': + i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw + away the node `a'. + ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is + thrown away, we throw away the node `a'. + 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b': + i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the + node `a'. + ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away, + we throw away the node `a'. */ + +#define STATE_NODE_CONTAINS(state,node) \ + ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) + +static reg_errcode_t +internal_function +sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) +{ + reg_errcode_t err; + int null_cnt = 0; + int str_idx = sctx->last_str_idx; + re_node_set cur_dest; + +#ifdef DEBUG + assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL); +#endif + + /* Build sifted state_log[str_idx]. It has the nodes which can epsilon + transit to the last_node and the last_node itself. */ + err = re_node_set_init_1 (&cur_dest, sctx->last_node); + if (BE (err != REG_NOERROR, 0)) + return err; + err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + + /* Then check each states in the state_log. */ + while (str_idx > 0) + { + /* Update counters. */ + null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; + if (null_cnt > mctx->max_mb_elem_len) + { + memset (sctx->sifted_states, '\0', + sizeof (re_dfastate_t *) * str_idx); + re_node_set_free (&cur_dest); + return REG_NOERROR; + } + re_node_set_empty (&cur_dest); + --str_idx; + + if (mctx->state_log[str_idx]) + { + err = build_sifted_states (mctx, sctx, str_idx, &cur_dest); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + + /* Add all the nodes which satisfy the following conditions: + - It can epsilon transit to a node in CUR_DEST. + - It is in CUR_SRC. + And update state_log. */ + err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + err = REG_NOERROR; + free_return: + re_node_set_free (&cur_dest); + return err; +} + +static reg_errcode_t +internal_function +build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, + int str_idx, re_node_set *cur_dest) +{ + const re_dfa_t *const dfa = mctx->dfa; + const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; + int i; + + /* Then build the next sifted state. + We build the next sifted state on `cur_dest', and update + `sifted_states[str_idx]' with `cur_dest'. + Note: + `cur_dest' is the sifted state from `state_log[str_idx + 1]'. + `cur_src' points the node_set of the old `state_log[str_idx]' + (with the epsilon nodes pre-filtered out). */ + for (i = 0; i < cur_src->nelem; i++) + { + int prev_node = cur_src->elems[i]; + int naccepted = 0; + int ret; + +#ifdef DEBUG + re_token_type_t type = dfa->nodes[prev_node].type; + assert (!IS_EPSILON_NODE (type)); +#endif +#ifdef RE_ENABLE_I18N + /* If the node may accept `multi byte'. */ + if (dfa->nodes[prev_node].accept_mb) + naccepted = sift_states_iter_mb (mctx, sctx, prev_node, + str_idx, sctx->last_str_idx); +#endif /* RE_ENABLE_I18N */ + + /* We don't check backreferences here. + See update_cur_sifted_state(). */ + if (!naccepted + && check_node_accept (mctx, dfa->nodes + prev_node, str_idx) + && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], + dfa->nexts[prev_node])) + naccepted = 1; + + if (naccepted == 0) + continue; + + if (sctx->limits.nelem) + { + int to_idx = str_idx + naccepted; + if (check_dst_limits (mctx, &sctx->limits, + dfa->nexts[prev_node], to_idx, + prev_node, str_idx)) + continue; + } + ret = re_node_set_insert (cur_dest, prev_node); + if (BE (ret == -1, 0)) + return REG_ESPACE; + } + + return REG_NOERROR; +} + +/* Helper functions. */ + +static reg_errcode_t +internal_function +clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx) +{ + int top = mctx->state_log_top; + + if (next_state_log_idx >= mctx->input.bufs_len + || (next_state_log_idx >= mctx->input.valid_len + && mctx->input.valid_len < mctx->input.len)) + { + reg_errcode_t err; + err = extend_buffers (mctx); + if (BE (err != REG_NOERROR, 0)) + return err; + } + + if (top < next_state_log_idx) + { + memset (mctx->state_log + top + 1, '\0', + sizeof (re_dfastate_t *) * (next_state_log_idx - top)); + mctx->state_log_top = next_state_log_idx; + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function +merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, + re_dfastate_t **src, int num) +{ + int st_idx; + reg_errcode_t err; + for (st_idx = 0; st_idx < num; ++st_idx) + { + if (dst[st_idx] == NULL) + dst[st_idx] = src[st_idx]; + else if (src[st_idx] != NULL) + { + re_node_set merged_set; + err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, + &src[st_idx]->nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); + re_node_set_free (&merged_set); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function +update_cur_sifted_state (const re_match_context_t *mctx, + re_sift_context_t *sctx, int str_idx, + re_node_set *dest_nodes) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err = REG_NOERROR; + const re_node_set *candidates; + candidates = ((mctx->state_log[str_idx] == NULL) ? NULL + : &mctx->state_log[str_idx]->nodes); + + if (dest_nodes->nelem == 0) + sctx->sifted_states[str_idx] = NULL; + else + { + if (candidates) + { + /* At first, add the nodes which can epsilon transit to a node in + DEST_NODE. */ + err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + + /* Then, check the limitations in the current sift_context. */ + if (sctx->limits.nelem) + { + err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, + mctx->bkref_ents, str_idx); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + + sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + } + + if (candidates && mctx->state_log[str_idx]->has_backref) + { + err = sift_states_bkref (mctx, sctx, str_idx, candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function +add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates) +{ + reg_errcode_t err = REG_NOERROR; + int i; + + re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + + if (!state->inveclosure.alloc) + { + err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem); + if (BE (err != REG_NOERROR, 0)) + return REG_ESPACE; + for (i = 0; i < dest_nodes->nelem; i++) + { + err = re_node_set_merge (&state->inveclosure, + dfa->inveclosures + dest_nodes->elems[i]); + if (BE (err != REG_NOERROR, 0)) + return REG_ESPACE; + } + } + return re_node_set_add_intersect (dest_nodes, candidates, + &state->inveclosure); +} + +static reg_errcode_t +internal_function +sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes, + const re_node_set *candidates) +{ + int ecl_idx; + reg_errcode_t err; + re_node_set *inv_eclosure = dfa->inveclosures + node; + re_node_set except_nodes; + re_node_set_init_empty (&except_nodes); + for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) + { + int cur_node = inv_eclosure->elems[ecl_idx]; + if (cur_node == node) + continue; + if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) + { + int edst1 = dfa->edests[cur_node].elems[0]; + int edst2 = ((dfa->edests[cur_node].nelem > 1) + ? dfa->edests[cur_node].elems[1] : -1); + if ((!re_node_set_contains (inv_eclosure, edst1) + && re_node_set_contains (dest_nodes, edst1)) + || (edst2 > 0 + && !re_node_set_contains (inv_eclosure, edst2) + && re_node_set_contains (dest_nodes, edst2))) + { + err = re_node_set_add_intersect (&except_nodes, candidates, + dfa->inveclosures + cur_node); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&except_nodes); + return err; + } + } + } + } + for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) + { + int cur_node = inv_eclosure->elems[ecl_idx]; + if (!re_node_set_contains (&except_nodes, cur_node)) + { + int idx = re_node_set_contains (dest_nodes, cur_node) - 1; + re_node_set_remove_at (dest_nodes, idx); + } + } + re_node_set_free (&except_nodes); + return REG_NOERROR; +} + +static int +internal_function +check_dst_limits (const re_match_context_t *mctx, re_node_set *limits, + int dst_node, int dst_idx, int src_node, int src_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + int lim_idx, src_pos, dst_pos; + + int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); + int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx); + for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) + { + int subexp_idx; + struct re_backref_cache_entry *ent; + ent = mctx->bkref_ents + limits->elems[lim_idx]; + subexp_idx = dfa->nodes[ent->node].opr.idx; + + dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], + subexp_idx, dst_node, dst_idx, + dst_bkref_idx); + src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], + subexp_idx, src_node, src_idx, + src_bkref_idx); + + /* In case of: + ( ) + ( ) + ( ) */ + if (src_pos == dst_pos) + continue; /* This is unrelated limitation. */ + else + return 1; + } + return 0; +} + +static int +internal_function +check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, + int subexp_idx, int from_node, int bkref_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + const re_node_set *eclosures = dfa->eclosures + from_node; + int node_idx; + + /* Else, we are on the boundary: examine the nodes on the epsilon + closure. */ + for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) + { + int node = eclosures->elems[node_idx]; + switch (dfa->nodes[node].type) + { + case OP_BACK_REF: + if (bkref_idx != -1) + { + struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx; + do + { + int dst, cpos; + + if (ent->node != node) + continue; + + if (subexp_idx < BITSET_WORD_BITS + && !(ent->eps_reachable_subexps_map + & ((bitset_word_t) 1 << subexp_idx))) + continue; + + /* Recurse trying to reach the OP_OPEN_SUBEXP and + OP_CLOSE_SUBEXP cases below. But, if the + destination node is the same node as the source + node, don't recurse because it would cause an + infinite loop: a regex that exhibits this behavior + is ()\1*\1* */ + dst = dfa->edests[node].elems[0]; + if (dst == from_node) + { + if (boundaries & 1) + return -1; + else /* if (boundaries & 2) */ + return 0; + } + + cpos = + check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, + dst, bkref_idx); + if (cpos == -1 /* && (boundaries & 1) */) + return -1; + if (cpos == 0 && (boundaries & 2)) + return 0; + + if (subexp_idx < BITSET_WORD_BITS) + ent->eps_reachable_subexps_map + &= ~((bitset_word_t) 1 << subexp_idx); + } + while (ent++->more); + } + break; + + case OP_OPEN_SUBEXP: + if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx) + return -1; + break; + + case OP_CLOSE_SUBEXP: + if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx) + return 0; + break; + + default: + break; + } + } + + return (boundaries & 2) ? 1 : 0; +} + +static int +internal_function +check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit, + int subexp_idx, int from_node, int str_idx, + int bkref_idx) +{ + struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; + int boundaries; + + /* If we are outside the range of the subexpression, return -1 or 1. */ + if (str_idx < lim->subexp_from) + return -1; + + if (lim->subexp_to < str_idx) + return 1; + + /* If we are within the subexpression, return 0. */ + boundaries = (str_idx == lim->subexp_from); + boundaries |= (str_idx == lim->subexp_to) << 1; + if (boundaries == 0) + return 0; + + /* Else, examine epsilon closure. */ + return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, + from_node, bkref_idx); +} + +/* Check the limitations of sub expressions LIMITS, and remove the nodes + which are against limitations from DEST_NODES. */ + +static reg_errcode_t +internal_function +check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates, re_node_set *limits, + struct re_backref_cache_entry *bkref_ents, int str_idx) +{ + reg_errcode_t err; + int node_idx, lim_idx; + + for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) + { + int subexp_idx; + struct re_backref_cache_entry *ent; + ent = bkref_ents + limits->elems[lim_idx]; + + if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) + continue; /* This is unrelated limitation. */ + + subexp_idx = dfa->nodes[ent->node].opr.idx; + if (ent->subexp_to == str_idx) + { + int ops_node = -1; + int cls_node = -1; + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + int node = dest_nodes->elems[node_idx]; + re_token_type_t type = dfa->nodes[node].type; + if (type == OP_OPEN_SUBEXP + && subexp_idx == dfa->nodes[node].opr.idx) + ops_node = node; + else if (type == OP_CLOSE_SUBEXP + && subexp_idx == dfa->nodes[node].opr.idx) + cls_node = node; + } + + /* Check the limitation of the open subexpression. */ + /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ + if (ops_node >= 0) + { + err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, + candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + } + + /* Check the limitation of the close subexpression. */ + if (cls_node >= 0) + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + int node = dest_nodes->elems[node_idx]; + if (!re_node_set_contains (dfa->inveclosures + node, + cls_node) + && !re_node_set_contains (dfa->eclosures + node, + cls_node)) + { + /* It is against this limitation. + Remove it form the current sifted state. */ + err = sub_epsilon_src_nodes (dfa, node, dest_nodes, + candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + --node_idx; + } + } + } + else /* (ent->subexp_to != str_idx) */ + { + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + int node = dest_nodes->elems[node_idx]; + re_token_type_t type = dfa->nodes[node].type; + if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) + { + if (subexp_idx != dfa->nodes[node].opr.idx) + continue; + /* It is against this limitation. + Remove it form the current sifted state. */ + err = sub_epsilon_src_nodes (dfa, node, dest_nodes, + candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + } + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function +sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, + int str_idx, const re_node_set *candidates) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + int node_idx, node; + re_sift_context_t local_sctx; + int first_idx = search_cur_bkref_entry (mctx, str_idx); + + if (first_idx == -1) + return REG_NOERROR; + + local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ + + for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) + { + int enabled_idx; + re_token_type_t type; + struct re_backref_cache_entry *entry; + node = candidates->elems[node_idx]; + type = dfa->nodes[node].type; + /* Avoid infinite loop for the REs like "()\1+". */ + if (node == sctx->last_node && str_idx == sctx->last_str_idx) + continue; + if (type != OP_BACK_REF) + continue; + + entry = mctx->bkref_ents + first_idx; + enabled_idx = first_idx; + do + { + int subexp_len; + int to_idx; + int dst_node; + int ret; + re_dfastate_t *cur_state; + + if (entry->node != node) + continue; + subexp_len = entry->subexp_to - entry->subexp_from; + to_idx = str_idx + subexp_len; + dst_node = (subexp_len ? dfa->nexts[node] + : dfa->edests[node].elems[0]); + + if (to_idx > sctx->last_str_idx + || sctx->sifted_states[to_idx] == NULL + || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) + || check_dst_limits (mctx, &sctx->limits, node, + str_idx, dst_node, to_idx)) + continue; + + if (local_sctx.sifted_states == NULL) + { + local_sctx = *sctx; + err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + local_sctx.last_node = node; + local_sctx.last_str_idx = str_idx; + ret = re_node_set_insert (&local_sctx.limits, enabled_idx); + if (BE (ret < 0, 0)) + { + err = REG_ESPACE; + goto free_return; + } + cur_state = local_sctx.sifted_states[str_idx]; + err = sift_states_backward (mctx, &local_sctx); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + if (sctx->limited_states != NULL) + { + err = merge_state_array (dfa, sctx->limited_states, + local_sctx.sifted_states, + str_idx + 1); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + local_sctx.sifted_states[str_idx] = cur_state; + re_node_set_remove (&local_sctx.limits, enabled_idx); + + /* mctx->bkref_ents may have changed, reload the pointer. */ + entry = mctx->bkref_ents + enabled_idx; + } + while (enabled_idx++, entry++->more); + } + err = REG_NOERROR; + free_return: + if (local_sctx.sifted_states != NULL) + { + re_node_set_free (&local_sctx.limits); + } + + return err; +} + + +#ifdef RE_ENABLE_I18N +static int +internal_function +sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, + int node_idx, int str_idx, int max_str_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + int naccepted; + /* Check the node can accept `multi byte'. */ + naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx); + if (naccepted > 0 && str_idx + naccepted <= max_str_idx && + !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted], + dfa->nexts[node_idx])) + /* The node can't accept the `multi byte', or the + destination was already thrown away, then the node + could't accept the current input `multi byte'. */ + naccepted = 0; + /* Otherwise, it is sure that the node could accept + `naccepted' bytes input. */ + return naccepted; +} +#endif /* RE_ENABLE_I18N */ + + +/* Functions for state transition. */ + +/* Return the next state to which the current state STATE will transit by + accepting the current input byte, and update STATE_LOG if necessary. + If STATE can accept a multibyte char/collating element/back reference + update the destination of STATE_LOG. */ + +static re_dfastate_t * +internal_function +transit_state (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *state) +{ + re_dfastate_t **trtable; + unsigned char ch; + +#ifdef RE_ENABLE_I18N + /* If the current state can accept multibyte. */ + if (BE (state->accept_mb, 0)) + { + *err = transit_state_mb (mctx, state); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + } +#endif /* RE_ENABLE_I18N */ + + /* Then decide the next state with the single byte. */ +#if 0 + if (0) + /* don't use transition table */ + return transit_state_sb (err, mctx, state); +#endif + + /* Use transition table */ + ch = re_string_fetch_byte (&mctx->input); + for (;;) + { + trtable = state->trtable; + if (BE (trtable != NULL, 1)) + return trtable[ch]; + + trtable = state->word_trtable; + if (BE (trtable != NULL, 1)) + { + unsigned int context; + context + = re_string_context_at (&mctx->input, + re_string_cur_idx (&mctx->input) - 1, + mctx->eflags); + if (IS_WORD_CONTEXT (context)) + return trtable[ch + SBC_MAX]; + else + return trtable[ch]; + } + + if (!build_trtable (mctx->dfa, state)) + { + *err = REG_ESPACE; + return NULL; + } + + /* Retry, we now have a transition table. */ + } +} + +/* Update the state_log if we need */ +re_dfastate_t * +internal_function +merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *next_state) +{ + const re_dfa_t *const dfa = mctx->dfa; + int cur_idx = re_string_cur_idx (&mctx->input); + + if (cur_idx > mctx->state_log_top) + { + mctx->state_log[cur_idx] = next_state; + mctx->state_log_top = cur_idx; + } + else if (mctx->state_log[cur_idx] == 0) + { + mctx->state_log[cur_idx] = next_state; + } + else + { + re_dfastate_t *pstate; + unsigned int context; + re_node_set next_nodes, *log_nodes, *table_nodes = NULL; + /* If (state_log[cur_idx] != 0), it implies that cur_idx is + the destination of a multibyte char/collating element/ + back reference. Then the next state is the union set of + these destinations and the results of the transition table. */ + pstate = mctx->state_log[cur_idx]; + log_nodes = pstate->entrance_nodes; + if (next_state != NULL) + { + table_nodes = next_state->entrance_nodes; + *err = re_node_set_init_union (&next_nodes, table_nodes, + log_nodes); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + } + else + next_nodes = *log_nodes; + /* Note: We already add the nodes of the initial state, + then we don't need to add them here. */ + + context = re_string_context_at (&mctx->input, + re_string_cur_idx (&mctx->input) - 1, + mctx->eflags); + next_state = mctx->state_log[cur_idx] + = re_acquire_state_context (err, dfa, &next_nodes, context); + /* We don't need to check errors here, since the return value of + this function is next_state and ERR is already set. */ + + if (table_nodes != NULL) + re_node_set_free (&next_nodes); + } + + if (BE (dfa->nbackref, 0) && next_state != NULL) + { + /* Check OP_OPEN_SUBEXP in the current state in case that we use them + later. We must check them here, since the back references in the + next state might use them. */ + *err = check_subexp_matching_top (mctx, &next_state->nodes, + cur_idx); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + + /* If the next state has back references. */ + if (next_state->has_backref) + { + *err = transit_state_bkref (mctx, &next_state->nodes); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + next_state = mctx->state_log[cur_idx]; + } + } + + return next_state; +} + +/* Skip bytes in the input that correspond to part of a + multi-byte match, then look in the log for a state + from which to restart matching. */ +re_dfastate_t * +internal_function +find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) +{ + re_dfastate_t *cur_state; + do + { + int max = mctx->state_log_top; + int cur_str_idx = re_string_cur_idx (&mctx->input); + + do + { + if (++cur_str_idx > max) + return NULL; + re_string_skip_bytes (&mctx->input, 1); + } + while (mctx->state_log[cur_str_idx] == NULL); + + cur_state = merge_state_with_log (err, mctx, NULL); + } + while (*err == REG_NOERROR && cur_state == NULL); + return cur_state; +} + +/* Helper functions for transit_state. */ + +/* From the node set CUR_NODES, pick up the nodes whose types are + OP_OPEN_SUBEXP and which have corresponding back references in the regular + expression. And register them to use them later for evaluating the + correspoding back references. */ + +static reg_errcode_t +internal_function +check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, + int str_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + int node_idx; + reg_errcode_t err; + + /* TODO: This isn't efficient. + Because there might be more than one nodes whose types are + OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all + nodes. + E.g. RE: (a){2} */ + for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) + { + int node = cur_nodes->elems[node_idx]; + if (dfa->nodes[node].type == OP_OPEN_SUBEXP + && dfa->nodes[node].opr.idx < BITSET_WORD_BITS + && (dfa->used_bkref_map + & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) + { + err = match_ctx_add_subtop (mctx, node, str_idx); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + return REG_NOERROR; +} + +#if 0 +/* Return the next state to which the current state STATE will transit by + accepting the current input byte. */ + +static re_dfastate_t * +transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *state) +{ + const re_dfa_t *const dfa = mctx->dfa; + re_node_set next_nodes; + re_dfastate_t *next_state; + int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input); + unsigned int context; + + *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt) + { + int cur_node = state->nodes.elems[node_cnt]; + if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx)) + { + *err = re_node_set_merge (&next_nodes, + dfa->eclosures + dfa->nexts[cur_node]); + if (BE (*err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return NULL; + } + } + } + context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags); + next_state = re_acquire_state_context (err, dfa, &next_nodes, context); + /* We don't need to check errors here, since the return value of + this function is next_state and ERR is already set. */ + + re_node_set_free (&next_nodes); + re_string_skip_bytes (&mctx->input, 1); + return next_state; +} +#endif + +#ifdef RE_ENABLE_I18N +static reg_errcode_t +internal_function +transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + int i; + + for (i = 0; i < pstate->nodes.nelem; ++i) + { + re_node_set dest_nodes, *new_nodes; + int cur_node_idx = pstate->nodes.elems[i]; + int naccepted, dest_idx; + unsigned int context; + re_dfastate_t *dest_state; + + if (!dfa->nodes[cur_node_idx].accept_mb) + continue; + + if (dfa->nodes[cur_node_idx].constraint) + { + context = re_string_context_at (&mctx->input, + re_string_cur_idx (&mctx->input), + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint, + context)) + continue; + } + + /* How many bytes the node can accept? */ + naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input, + re_string_cur_idx (&mctx->input)); + if (naccepted == 0) + continue; + + /* The node can accepts `naccepted' bytes. */ + dest_idx = re_string_cur_idx (&mctx->input) + naccepted; + mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted + : mctx->max_mb_elem_len); + err = clean_state_log_if_needed (mctx, dest_idx); + if (BE (err != REG_NOERROR, 0)) + return err; +#ifdef DEBUG + assert (dfa->nexts[cur_node_idx] != -1); +#endif + new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx]; + + dest_state = mctx->state_log[dest_idx]; + if (dest_state == NULL) + dest_nodes = *new_nodes; + else + { + err = re_node_set_init_union (&dest_nodes, + dest_state->entrance_nodes, new_nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + } + context = re_string_context_at (&mctx->input, dest_idx - 1, + mctx->eflags); + mctx->state_log[dest_idx] + = re_acquire_state_context (&err, dfa, &dest_nodes, context); + if (dest_state != NULL) + re_node_set_free (&dest_nodes); + if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0)) + return err; + } + return REG_NOERROR; +} +#endif /* RE_ENABLE_I18N */ + +static reg_errcode_t +internal_function +transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + int i; + int cur_str_idx = re_string_cur_idx (&mctx->input); + + for (i = 0; i < nodes->nelem; ++i) + { + int dest_str_idx, prev_nelem, bkc_idx; + int node_idx = nodes->elems[i]; + unsigned int context; + const re_token_t *node = dfa->nodes + node_idx; + re_node_set *new_dest_nodes; + + /* Check whether `node' is a backreference or not. */ + if (node->type != OP_BACK_REF) + continue; + + if (node->constraint) + { + context = re_string_context_at (&mctx->input, cur_str_idx, + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) + continue; + } + + /* `node' is a backreference. + Check the substring which the substring matched. */ + bkc_idx = mctx->nbkref_ents; + err = get_subexp (mctx, node_idx, cur_str_idx); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + + /* And add the epsilon closures (which is `new_dest_nodes') of + the backreference to appropriate state_log. */ +#ifdef DEBUG + assert (dfa->nexts[node_idx] != -1); +#endif + for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) + { + int subexp_len; + re_dfastate_t *dest_state; + struct re_backref_cache_entry *bkref_ent; + bkref_ent = mctx->bkref_ents + bkc_idx; + if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) + continue; + subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; + new_dest_nodes = (subexp_len == 0 + ? dfa->eclosures + dfa->edests[node_idx].elems[0] + : dfa->eclosures + dfa->nexts[node_idx]); + dest_str_idx = (cur_str_idx + bkref_ent->subexp_to + - bkref_ent->subexp_from); + context = re_string_context_at (&mctx->input, dest_str_idx - 1, + mctx->eflags); + dest_state = mctx->state_log[dest_str_idx]; + prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 + : mctx->state_log[cur_str_idx]->nodes.nelem); + /* Add `new_dest_node' to state_log. */ + if (dest_state == NULL) + { + mctx->state_log[dest_str_idx] + = re_acquire_state_context (&err, dfa, new_dest_nodes, + context); + if (BE (mctx->state_log[dest_str_idx] == NULL + && err != REG_NOERROR, 0)) + goto free_return; + } + else + { + re_node_set dest_nodes; + err = re_node_set_init_union (&dest_nodes, + dest_state->entrance_nodes, + new_dest_nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&dest_nodes); + goto free_return; + } + mctx->state_log[dest_str_idx] + = re_acquire_state_context (&err, dfa, &dest_nodes, context); + re_node_set_free (&dest_nodes); + if (BE (mctx->state_log[dest_str_idx] == NULL + && err != REG_NOERROR, 0)) + goto free_return; + } + /* We need to check recursively if the backreference can epsilon + transit. */ + if (subexp_len == 0 + && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) + { + err = check_subexp_matching_top (mctx, new_dest_nodes, + cur_str_idx); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + err = transit_state_bkref (mctx, new_dest_nodes); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + } + } + err = REG_NOERROR; + free_return: + return err; +} + +/* Enumerate all the candidates which the backreference BKREF_NODE can match + at BKREF_STR_IDX, and register them by match_ctx_add_entry(). + Note that we might collect inappropriate candidates here. + However, the cost of checking them strictly here is too high, then we + delay these checking for prune_impossible_nodes(). */ + +static reg_errcode_t +internal_function +get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + int subexp_num, sub_top_idx; + const char *buf = (const char *) re_string_get_buffer (&mctx->input); + /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ + int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx); + if (cache_idx != -1) + { + const struct re_backref_cache_entry *entry + = mctx->bkref_ents + cache_idx; + do + if (entry->node == bkref_node) + return REG_NOERROR; /* We already checked it. */ + while (entry++->more); + } + + subexp_num = dfa->nodes[bkref_node].opr.idx; + + /* For each sub expression */ + for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) + { + reg_errcode_t err; + re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; + re_sub_match_last_t *sub_last; + int sub_last_idx, sl_str, bkref_str_off; + + if (dfa->nodes[sub_top->node].opr.idx != subexp_num) + continue; /* It isn't related. */ + + sl_str = sub_top->str_idx; + bkref_str_off = bkref_str_idx; + /* At first, check the last node of sub expressions we already + evaluated. */ + for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) + { + int sl_str_diff; + sub_last = sub_top->lasts[sub_last_idx]; + sl_str_diff = sub_last->str_idx - sl_str; + /* The matched string by the sub expression match with the substring + at the back reference? */ + if (sl_str_diff > 0) + { + if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0)) + { + /* Not enough chars for a successful match. */ + if (bkref_str_off + sl_str_diff > mctx->input.len) + break; + + err = clean_state_log_if_needed (mctx, + bkref_str_off + + sl_str_diff); + if (BE (err != REG_NOERROR, 0)) + return err; + buf = (const char *) re_string_get_buffer (&mctx->input); + } + if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) + /* We don't need to search this sub expression any more. */ + break; + } + bkref_str_off += sl_str_diff; + sl_str += sl_str_diff; + err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, + bkref_str_idx); + + /* Reload buf, since the preceding call might have reallocated + the buffer. */ + buf = (const char *) re_string_get_buffer (&mctx->input); + + if (err == REG_NOMATCH) + continue; + if (BE (err != REG_NOERROR, 0)) + return err; + } + + if (sub_last_idx < sub_top->nlasts) + continue; + if (sub_last_idx > 0) + ++sl_str; + /* Then, search for the other last nodes of the sub expression. */ + for (; sl_str <= bkref_str_idx; ++sl_str) + { + int cls_node, sl_str_off; + const re_node_set *nodes; + sl_str_off = sl_str - sub_top->str_idx; + /* The matched string by the sub expression match with the substring + at the back reference? */ + if (sl_str_off > 0) + { + if (BE (bkref_str_off >= mctx->input.valid_len, 0)) + { + /* If we are at the end of the input, we cannot match. */ + if (bkref_str_off >= mctx->input.len) + break; + + err = extend_buffers (mctx); + if (BE (err != REG_NOERROR, 0)) + return err; + + buf = (const char *) re_string_get_buffer (&mctx->input); + } + if (buf [bkref_str_off++] != buf[sl_str - 1]) + break; /* We don't need to search this sub expression + any more. */ + } + if (mctx->state_log[sl_str] == NULL) + continue; + /* Does this state have a ')' of the sub expression? */ + nodes = &mctx->state_log[sl_str]->nodes; + cls_node = find_subexp_node (dfa, nodes, subexp_num, + OP_CLOSE_SUBEXP); + if (cls_node == -1) + continue; /* No. */ + if (sub_top->path == NULL) + { + sub_top->path = calloc (sizeof (state_array_t), + sl_str - sub_top->str_idx + 1); + if (sub_top->path == NULL) + return REG_ESPACE; + } + /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node + in the current context? */ + err = check_arrival (mctx, sub_top->path, sub_top->node, + sub_top->str_idx, cls_node, sl_str, + OP_CLOSE_SUBEXP); + if (err == REG_NOMATCH) + continue; + if (BE (err != REG_NOERROR, 0)) + return err; + sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str); + if (BE (sub_last == NULL, 0)) + return REG_ESPACE; + err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, + bkref_str_idx); + if (err == REG_NOMATCH) + continue; + } + } + return REG_NOERROR; +} + +/* Helper functions for get_subexp(). */ + +/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. + If it can arrive, register the sub expression expressed with SUB_TOP + and SUB_LAST. */ + +static reg_errcode_t +internal_function +get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top, + re_sub_match_last_t *sub_last, int bkref_node, int bkref_str) +{ + reg_errcode_t err; + int to_idx; + /* Can the subexpression arrive the back reference? */ + err = check_arrival (mctx, &sub_last->path, sub_last->node, + sub_last->str_idx, bkref_node, bkref_str, + OP_OPEN_SUBEXP); + if (err != REG_NOERROR) + return err; + err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx, + sub_last->str_idx); + if (BE (err != REG_NOERROR, 0)) + return err; + to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; + return clean_state_log_if_needed (mctx, to_idx); +} + +/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. + Search '(' if FL_OPEN, or search ')' otherwise. + TODO: This function isn't efficient... + Because there might be more than one nodes whose types are + OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all + nodes. + E.g. RE: (a){2} */ + +static int +internal_function +find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, + int subexp_idx, int type) +{ + int cls_idx; + for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) + { + int cls_node = nodes->elems[cls_idx]; + const re_token_t *node = dfa->nodes + cls_node; + if (node->type == type + && node->opr.idx == subexp_idx) + return cls_node; + } + return -1; +} + +/* Check whether the node TOP_NODE at TOP_STR can arrive to the node + LAST_NODE at LAST_STR. We record the path onto PATH since it will be + heavily reused. + Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ + +static reg_errcode_t +internal_function +check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node, + int top_str, int last_node, int last_str, int type) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err = REG_NOERROR; + int subexp_num, backup_cur_idx, str_idx, null_cnt; + re_dfastate_t *cur_state = NULL; + re_node_set *cur_nodes, next_nodes; + re_dfastate_t **backup_state_log; + unsigned int context; + + subexp_num = dfa->nodes[top_node].opr.idx; + /* Extend the buffer if we need. */ + if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0)) + { + re_dfastate_t **new_array; + int old_alloc = path->alloc; + path->alloc += last_str + mctx->max_mb_elem_len + 1; + new_array = re_realloc (path->array, re_dfastate_t *, path->alloc); + if (BE (new_array == NULL, 0)) + { + path->alloc = old_alloc; + return REG_ESPACE; + } + path->array = new_array; + memset (new_array + old_alloc, '\0', + sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); + } + + str_idx = path->next_idx ? path->next_idx : top_str; + + /* Temporary modify MCTX. */ + backup_state_log = mctx->state_log; + backup_cur_idx = mctx->input.cur_idx; + mctx->state_log = path->array; + mctx->input.cur_idx = str_idx; + + /* Setup initial node set. */ + context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); + if (str_idx == top_str) + { + err = re_node_set_init_1 (&next_nodes, top_node); + if (BE (err != REG_NOERROR, 0)) + return err; + err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + else + { + cur_state = mctx->state_log[str_idx]; + if (cur_state && cur_state->has_backref) + { + err = re_node_set_init_copy (&next_nodes, &cur_state->nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + } + else + re_node_set_init_empty (&next_nodes); + } + if (str_idx == top_str || (cur_state && cur_state->has_backref)) + { + if (next_nodes.nelem) + { + err = expand_bkref_cache (mctx, &next_nodes, str_idx, + subexp_num, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); + if (BE (cur_state == NULL && err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + mctx->state_log[str_idx] = cur_state; + } + + for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) + { + re_node_set_empty (&next_nodes); + if (mctx->state_log[str_idx + 1]) + { + err = re_node_set_merge (&next_nodes, + &mctx->state_log[str_idx + 1]->nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + if (cur_state) + { + err = check_arrival_add_next_nodes (mctx, str_idx, + &cur_state->non_eps_nodes, + &next_nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + ++str_idx; + if (next_nodes.nelem) + { + err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + err = expand_bkref_cache (mctx, &next_nodes, str_idx, + subexp_num, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); + cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); + if (BE (cur_state == NULL && err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + mctx->state_log[str_idx] = cur_state; + null_cnt = cur_state == NULL ? null_cnt + 1 : 0; + } + re_node_set_free (&next_nodes); + cur_nodes = (mctx->state_log[last_str] == NULL ? NULL + : &mctx->state_log[last_str]->nodes); + path->next_idx = str_idx; + + /* Fix MCTX. */ + mctx->state_log = backup_state_log; + mctx->input.cur_idx = backup_cur_idx; + + /* Then check the current node set has the node LAST_NODE. */ + if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node)) + return REG_NOERROR; + + return REG_NOMATCH; +} + +/* Helper functions for check_arrival. */ + +/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them + to NEXT_NODES. + TODO: This function is similar to the functions transit_state*(), + however this function has many additional works. + Can't we unify them? */ + +static reg_errcode_t +internal_function +check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx, + re_node_set *cur_nodes, re_node_set *next_nodes) +{ + const re_dfa_t *const dfa = mctx->dfa; + int result; + int cur_idx; +#ifdef RE_ENABLE_I18N + reg_errcode_t err = REG_NOERROR; +#endif + re_node_set union_set; + re_node_set_init_empty (&union_set); + for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) + { + int naccepted = 0; + int cur_node = cur_nodes->elems[cur_idx]; +#ifdef DEBUG + re_token_type_t type = dfa->nodes[cur_node].type; + assert (!IS_EPSILON_NODE (type)); +#endif +#ifdef RE_ENABLE_I18N + /* If the node may accept `multi byte'. */ + if (dfa->nodes[cur_node].accept_mb) + { + naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input, + str_idx); + if (naccepted > 1) + { + re_dfastate_t *dest_state; + int next_node = dfa->nexts[cur_node]; + int next_idx = str_idx + naccepted; + dest_state = mctx->state_log[next_idx]; + re_node_set_empty (&union_set); + if (dest_state) + { + err = re_node_set_merge (&union_set, &dest_state->nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&union_set); + return err; + } + } + result = re_node_set_insert (&union_set, next_node); + if (BE (result < 0, 0)) + { + re_node_set_free (&union_set); + return REG_ESPACE; + } + mctx->state_log[next_idx] = re_acquire_state (&err, dfa, + &union_set); + if (BE (mctx->state_log[next_idx] == NULL + && err != REG_NOERROR, 0)) + { + re_node_set_free (&union_set); + return err; + } + } + } +#endif /* RE_ENABLE_I18N */ + if (naccepted + || check_node_accept (mctx, dfa->nodes + cur_node, str_idx)) + { + result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]); + if (BE (result < 0, 0)) + { + re_node_set_free (&union_set); + return REG_ESPACE; + } + } + } + re_node_set_free (&union_set); + return REG_NOERROR; +} + +/* For all the nodes in CUR_NODES, add the epsilon closures of them to + CUR_NODES, however exclude the nodes which are: + - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. + - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. +*/ + +static reg_errcode_t +internal_function +check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, + int ex_subexp, int type) +{ + reg_errcode_t err; + int idx, outside_node; + re_node_set new_nodes; +#ifdef DEBUG + assert (cur_nodes->nelem); +#endif + err = re_node_set_alloc (&new_nodes, cur_nodes->nelem); + if (BE (err != REG_NOERROR, 0)) + return err; + /* Create a new node set NEW_NODES with the nodes which are epsilon + closures of the node in CUR_NODES. */ + + for (idx = 0; idx < cur_nodes->nelem; ++idx) + { + int cur_node = cur_nodes->elems[idx]; + const re_node_set *eclosure = dfa->eclosures + cur_node; + outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type); + if (outside_node == -1) + { + /* There are no problematic nodes, just merge them. */ + err = re_node_set_merge (&new_nodes, eclosure); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&new_nodes); + return err; + } + } + else + { + /* There are problematic nodes, re-calculate incrementally. */ + err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node, + ex_subexp, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&new_nodes); + return err; + } + } + } + re_node_set_free (cur_nodes); + *cur_nodes = new_nodes; + return REG_NOERROR; +} + +/* Helper function for check_arrival_expand_ecl. + Check incrementally the epsilon closure of TARGET, and if it isn't + problematic append it to DST_NODES. */ + +static reg_errcode_t +internal_function +check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes, + int target, int ex_subexp, int type) +{ + int cur_node; + for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);) + { + int err; + + if (dfa->nodes[cur_node].type == type + && dfa->nodes[cur_node].opr.idx == ex_subexp) + { + if (type == OP_CLOSE_SUBEXP) + { + err = re_node_set_insert (dst_nodes, cur_node); + if (BE (err == -1, 0)) + return REG_ESPACE; + } + break; + } + err = re_node_set_insert (dst_nodes, cur_node); + if (BE (err == -1, 0)) + return REG_ESPACE; + if (dfa->edests[cur_node].nelem == 0) + break; + if (dfa->edests[cur_node].nelem == 2) + { + err = check_arrival_expand_ecl_sub (dfa, dst_nodes, + dfa->edests[cur_node].elems[1], + ex_subexp, type); + if (BE (err != REG_NOERROR, 0)) + return err; + } + cur_node = dfa->edests[cur_node].elems[0]; + } + return REG_NOERROR; +} + + +/* For all the back references in the current state, calculate the + destination of the back references by the appropriate entry + in MCTX->BKREF_ENTS. */ + +static reg_errcode_t +internal_function +expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, + int cur_str, int subexp_num, int type) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + int cache_idx_start = search_cur_bkref_entry (mctx, cur_str); + struct re_backref_cache_entry *ent; + + if (cache_idx_start == -1) + return REG_NOERROR; + + restart: + ent = mctx->bkref_ents + cache_idx_start; + do + { + int to_idx, next_node; + + /* Is this entry ENT is appropriate? */ + if (!re_node_set_contains (cur_nodes, ent->node)) + continue; /* No. */ + + to_idx = cur_str + ent->subexp_to - ent->subexp_from; + /* Calculate the destination of the back reference, and append it + to MCTX->STATE_LOG. */ + if (to_idx == cur_str) + { + /* The backreference did epsilon transit, we must re-check all the + node in the current state. */ + re_node_set new_dests; + reg_errcode_t err2, err3; + next_node = dfa->edests[ent->node].elems[0]; + if (re_node_set_contains (cur_nodes, next_node)) + continue; + err = re_node_set_init_1 (&new_dests, next_node); + err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type); + err3 = re_node_set_merge (cur_nodes, &new_dests); + re_node_set_free (&new_dests); + if (BE (err != REG_NOERROR || err2 != REG_NOERROR + || err3 != REG_NOERROR, 0)) + { + err = (err != REG_NOERROR ? err + : (err2 != REG_NOERROR ? err2 : err3)); + return err; + } + /* TODO: It is still inefficient... */ + goto restart; + } + else + { + re_node_set union_set; + next_node = dfa->nexts[ent->node]; + if (mctx->state_log[to_idx]) + { + int ret; + if (re_node_set_contains (&mctx->state_log[to_idx]->nodes, + next_node)) + continue; + err = re_node_set_init_copy (&union_set, + &mctx->state_log[to_idx]->nodes); + ret = re_node_set_insert (&union_set, next_node); + if (BE (err != REG_NOERROR || ret < 0, 0)) + { + re_node_set_free (&union_set); + err = err != REG_NOERROR ? err : REG_ESPACE; + return err; + } + } + else + { + err = re_node_set_init_1 (&union_set, next_node); + if (BE (err != REG_NOERROR, 0)) + return err; + } + mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set); + re_node_set_free (&union_set); + if (BE (mctx->state_log[to_idx] == NULL + && err != REG_NOERROR, 0)) + return err; + } + } + while (ent++->more); + return REG_NOERROR; +} + +/* Build transition table for the state. + Return 1 if succeeded, otherwise return NULL. */ + +static int +internal_function +build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) +{ + reg_errcode_t err; + int i, j, ch, need_word_trtable = 0; + bitset_word_t elem, mask; + bool dests_node_malloced = false; + bool dest_states_malloced = false; + int ndests; /* Number of the destination states from `state'. */ + re_dfastate_t **trtable; + re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; + re_node_set follows, *dests_node; + bitset_t *dests_ch; + bitset_t acceptable; + + struct dests_alloc + { + re_node_set dests_node[SBC_MAX]; + bitset_t dests_ch[SBC_MAX]; + } *dests_alloc; + + /* We build DFA states which corresponds to the destination nodes + from `state'. `dests_node[i]' represents the nodes which i-th + destination state contains, and `dests_ch[i]' represents the + characters which i-th destination state accepts. */ +#ifdef HAVE_ALLOCA + if (__libc_use_alloca (sizeof (struct dests_alloc))) + dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); + else +#endif + { + dests_alloc = re_malloc (struct dests_alloc, 1); + if (BE (dests_alloc == NULL, 0)) + return 0; + dests_node_malloced = true; + } + dests_node = dests_alloc->dests_node; + dests_ch = dests_alloc->dests_ch; + + /* Initialize transiton table. */ + state->word_trtable = state->trtable = NULL; + + /* At first, group all nodes belonging to `state' into several + destinations. */ + ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); + if (BE (ndests <= 0, 0)) + { + if (dests_node_malloced) + free (dests_alloc); + /* Return 0 in case of an error, 1 otherwise. */ + if (ndests == 0) + { + state->trtable = (re_dfastate_t **) + calloc (sizeof (re_dfastate_t *), SBC_MAX); + return 1; + } + return 0; + } + + err = re_node_set_alloc (&follows, ndests + 1); + if (BE (err != REG_NOERROR, 0)) + goto out_free; + + /* Avoid arithmetic overflow in size calculation. */ + if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) + / (3 * sizeof (re_dfastate_t *))) + < ndests), + 0)) + goto out_free; + +#ifdef HAVE_ALLOCA + if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX + + ndests * 3 * sizeof (re_dfastate_t *))) + dest_states = (re_dfastate_t **) + alloca (ndests * 3 * sizeof (re_dfastate_t *)); + else +#endif + { + dest_states = (re_dfastate_t **) + malloc (ndests * 3 * sizeof (re_dfastate_t *)); + if (BE (dest_states == NULL, 0)) + { +out_free: + if (dest_states_malloced) + free (dest_states); + re_node_set_free (&follows); + for (i = 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + if (dests_node_malloced) + free (dests_alloc); + return 0; + } + dest_states_malloced = true; + } + dest_states_word = dest_states + ndests; + dest_states_nl = dest_states_word + ndests; + bitset_empty (acceptable); + + /* Then build the states for all destinations. */ + for (i = 0; i < ndests; ++i) + { + int next_node; + re_node_set_empty (&follows); + /* Merge the follows of this destination states. */ + for (j = 0; j < dests_node[i].nelem; ++j) + { + next_node = dfa->nexts[dests_node[i].elems[j]]; + if (next_node != -1) + { + err = re_node_set_merge (&follows, dfa->eclosures + next_node); + if (BE (err != REG_NOERROR, 0)) + goto out_free; + } + } + dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); + if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0)) + goto out_free; + /* If the new state has context constraint, + build appropriate states for these contexts. */ + if (dest_states[i]->has_constraint) + { + dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, + CONTEXT_WORD); + if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) + goto out_free; + + if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) + need_word_trtable = 1; + + dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, + CONTEXT_NEWLINE); + if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0)) + goto out_free; + } + else + { + dest_states_word[i] = dest_states[i]; + dest_states_nl[i] = dest_states[i]; + } + bitset_merge (acceptable, dests_ch[i]); + } + + if (!BE (need_word_trtable, 0)) + { + /* We don't care about whether the following character is a word + character, or we are in a single-byte character set so we can + discern by looking at the character code: allocate a + 256-entry transition table. */ + trtable = state->trtable = + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); + if (BE (trtable == NULL, 0)) + goto out_free; + + /* For all characters ch...: */ + for (i = 0; i < BITSET_WORDS; ++i) + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; + elem; + mask <<= 1, elem >>= 1, ++ch) + if (BE (elem & 1, 0)) + { + /* There must be exactly one destination which accepts + character ch. See group_nodes_into_DFAstates. */ + for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) + ; + + /* j-th destination accepts the word character ch. */ + if (dfa->word_char[i] & mask) + trtable[ch] = dest_states_word[j]; + else + trtable[ch] = dest_states[j]; + } + } + else + { + /* We care about whether the following character is a word + character, and we are in a multi-byte character set: discern + by looking at the character code: build two 256-entry + transition tables, one starting at trtable[0] and one + starting at trtable[SBC_MAX]. */ + trtable = state->word_trtable = + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); + if (BE (trtable == NULL, 0)) + goto out_free; + + /* For all characters ch...: */ + for (i = 0; i < BITSET_WORDS; ++i) + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; + elem; + mask <<= 1, elem >>= 1, ++ch) + if (BE (elem & 1, 0)) + { + /* There must be exactly one destination which accepts + character ch. See group_nodes_into_DFAstates. */ + for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) + ; + + /* j-th destination accepts the word character ch. */ + trtable[ch] = dest_states[j]; + trtable[ch + SBC_MAX] = dest_states_word[j]; + } + } + + /* new line */ + if (bitset_contain (acceptable, NEWLINE_CHAR)) + { + /* The current state accepts newline character. */ + for (j = 0; j < ndests; ++j) + if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) + { + /* k-th destination accepts newline character. */ + trtable[NEWLINE_CHAR] = dest_states_nl[j]; + if (need_word_trtable) + trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; + /* There must be only one destination which accepts + newline. See group_nodes_into_DFAstates. */ + break; + } + } + + if (dest_states_malloced) + free (dest_states); + + re_node_set_free (&follows); + for (i = 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + + if (dests_node_malloced) + free (dests_alloc); + + return 1; +} + +/* Group all nodes belonging to STATE into several destinations. + Then for all destinations, set the nodes belonging to the destination + to DESTS_NODE[i] and set the characters accepted by the destination + to DEST_CH[i]. This function return the number of destinations. */ + +static int +internal_function +group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, + re_node_set *dests_node, bitset_t *dests_ch) +{ + reg_errcode_t err; + int result; + int i, j, k; + int ndests; /* Number of the destinations from `state'. */ + bitset_t accepts; /* Characters a node can accept. */ + const re_node_set *cur_nodes = &state->nodes; + bitset_empty (accepts); + ndests = 0; + + /* For all the nodes belonging to `state', */ + for (i = 0; i < cur_nodes->nelem; ++i) + { + re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; + re_token_type_t type = node->type; + unsigned int constraint = node->constraint; + + /* Enumerate all single byte character this node can accept. */ + if (type == CHARACTER) + bitset_set (accepts, node->opr.c); + else if (type == SIMPLE_BRACKET) + { + bitset_merge (accepts, node->opr.sbcset); + } + else if (type == OP_PERIOD) + { +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + bitset_merge (accepts, dfa->sb_char); + else +#endif + bitset_set_all (accepts); + if (!(dfa->syntax & RE_DOT_NEWLINE)) + bitset_clear (accepts, '\n'); + if (dfa->syntax & RE_DOT_NOT_NULL) + bitset_clear (accepts, '\0'); + } +#ifdef RE_ENABLE_I18N + else if (type == OP_UTF8_PERIOD) + { + memset (accepts, '\xff', sizeof (bitset_t) / 2); + if (!(dfa->syntax & RE_DOT_NEWLINE)) + bitset_clear (accepts, '\n'); + if (dfa->syntax & RE_DOT_NOT_NULL) + bitset_clear (accepts, '\0'); + } +#endif + else + continue; + + /* Check the `accepts' and sift the characters which are not + match it the context. */ + if (constraint) + { + if (constraint & NEXT_NEWLINE_CONSTRAINT) + { + bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); + bitset_empty (accepts); + if (accepts_newline) + bitset_set (accepts, NEWLINE_CHAR); + else + continue; + } + if (constraint & NEXT_ENDBUF_CONSTRAINT) + { + bitset_empty (accepts); + continue; + } + + if (constraint & NEXT_WORD_CONSTRAINT) + { + bitset_word_t any_set = 0; + if (type == CHARACTER && !node->word_char) + { + bitset_empty (accepts); + continue; + } +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j])); + else +#endif + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= dfa->word_char[j]); + if (!any_set) + continue; + } + if (constraint & NEXT_NOTWORD_CONSTRAINT) + { + bitset_word_t any_set = 0; + if (type == CHARACTER && node->word_char) + { + bitset_empty (accepts); + continue; + } +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j])); + else +#endif + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= ~dfa->word_char[j]); + if (!any_set) + continue; + } + } + + /* Then divide `accepts' into DFA states, or create a new + state. Above, we make sure that accepts is not empty. */ + for (j = 0; j < ndests; ++j) + { + bitset_t intersec; /* Intersection sets, see below. */ + bitset_t remains; + /* Flags, see below. */ + bitset_word_t has_intersec, not_subset, not_consumed; + + /* Optimization, skip if this state doesn't accept the character. */ + if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) + continue; + + /* Enumerate the intersection set of this state and `accepts'. */ + has_intersec = 0; + for (k = 0; k < BITSET_WORDS; ++k) + has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; + /* And skip if the intersection set is empty. */ + if (!has_intersec) + continue; + + /* Then check if this state is a subset of `accepts'. */ + not_subset = not_consumed = 0; + for (k = 0; k < BITSET_WORDS; ++k) + { + not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; + not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; + } + + /* If this state isn't a subset of `accepts', create a + new group state, which has the `remains'. */ + if (not_subset) + { + bitset_copy (dests_ch[ndests], remains); + bitset_copy (dests_ch[j], intersec); + err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); + if (BE (err != REG_NOERROR, 0)) + goto error_return; + ++ndests; + } + + /* Put the position in the current group. */ + result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); + if (BE (result < 0, 0)) + goto error_return; + + /* If all characters are consumed, go to next node. */ + if (!not_consumed) + break; + } + /* Some characters remain, create a new group. */ + if (j == ndests) + { + bitset_copy (dests_ch[ndests], accepts); + err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); + if (BE (err != REG_NOERROR, 0)) + goto error_return; + ++ndests; + bitset_empty (accepts); + } + } + return ndests; + error_return: + for (j = 0; j < ndests; ++j) + re_node_set_free (dests_node + j); + return -1; +} + +#ifdef RE_ENABLE_I18N +/* Check how many bytes the node `dfa->nodes[node_idx]' accepts. + Return the number of the bytes the node accepts. + STR_IDX is the current index of the input string. + + This function handles the nodes which can accept one character, or + one collating element like '.', '[a-z]', opposite to the other nodes + can only accept one byte. */ + +static int +internal_function +check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, + const re_string_t *input, int str_idx) +{ + const re_token_t *node = dfa->nodes + node_idx; + int char_len, elem_len; + int i; + wint_t wc; + + if (BE (node->type == OP_UTF8_PERIOD, 0)) + { + unsigned char c = re_string_byte_at (input, str_idx), d; + if (BE (c < 0xc2, 1)) + return 0; + + if (str_idx + 2 > input->len) + return 0; + + d = re_string_byte_at (input, str_idx + 1); + if (c < 0xe0) + return (d < 0x80 || d > 0xbf) ? 0 : 2; + else if (c < 0xf0) + { + char_len = 3; + if (c == 0xe0 && d < 0xa0) + return 0; + } + else if (c < 0xf8) + { + char_len = 4; + if (c == 0xf0 && d < 0x90) + return 0; + } + else if (c < 0xfc) + { + char_len = 5; + if (c == 0xf8 && d < 0x88) + return 0; + } + else if (c < 0xfe) + { + char_len = 6; + if (c == 0xfc && d < 0x84) + return 0; + } + else + return 0; + + if (str_idx + char_len > input->len) + return 0; + + for (i = 1; i < char_len; ++i) + { + d = re_string_byte_at (input, str_idx + i); + if (d < 0x80 || d > 0xbf) + return 0; + } + return char_len; + } + + char_len = re_string_char_size_at (input, str_idx); + if (node->type == OP_PERIOD) + { + if (char_len <= 1) + return 0; + /* FIXME: I don't think this if is needed, as both '\n' + and '\0' are char_len == 1. */ + /* '.' accepts any one character except the following two cases. */ + if ((!(dfa->syntax & RE_DOT_NEWLINE) && + re_string_byte_at (input, str_idx) == '\n') || + ((dfa->syntax & RE_DOT_NOT_NULL) && + re_string_byte_at (input, str_idx) == '\0')) + return 0; + return char_len; + } + + elem_len = re_string_elem_size_at (input, str_idx); + wc = __btowc(*(input->mbs+str_idx)); + if (((elem_len <= 1 && char_len <= 1) || char_len == 0) && (wc != WEOF && wc < SBC_MAX)) + return 0; + + if (node->type == COMPLEX_BRACKET) + { + const re_charset_t *cset = node->opr.mbcset; +# ifdef _LIBC + const unsigned char *pin + = ((const unsigned char *) re_string_get_buffer (input) + str_idx); + int j; + uint32_t nrules; +# endif /* _LIBC */ + int match_len = 0; + wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars) + ? re_string_wchar_at (input, str_idx) : 0); + + /* match with multibyte character? */ + for (i = 0; i < cset->nmbchars; ++i) + if (wc == cset->mbchars[i]) + { + match_len = char_len; + goto check_node_accept_bytes_match; + } + /* match with character_class? */ + for (i = 0; i < cset->nchar_classes; ++i) + { + wctype_t wt = cset->char_classes[i]; + if (__iswctype (wc, wt)) + { + match_len = char_len; + goto check_node_accept_bytes_match; + } + } + +# ifdef _LIBC + nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules != 0) + { + unsigned int in_collseq = 0; + const int32_t *table, *indirect; + const unsigned char *weights, *extra; + const char *collseqwc; + /* This #include defines a local function! */ +# include + + /* match with collating_symbol? */ + if (cset->ncoll_syms) + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); + for (i = 0; i < cset->ncoll_syms; ++i) + { + const unsigned char *coll_sym = extra + cset->coll_syms[i]; + /* Compare the length of input collating element and + the length of current collating element. */ + if (*coll_sym != elem_len) + continue; + /* Compare each bytes. */ + for (j = 0; j < *coll_sym; j++) + if (pin[j] != coll_sym[1 + j]) + break; + if (j == *coll_sym) + { + /* Match if every bytes is equal. */ + match_len = j; + goto check_node_accept_bytes_match; + } + } + + if (cset->nranges) + { + if (elem_len <= char_len) + { + collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); + in_collseq = __collseq_table_lookup (collseqwc, wc); + } + else + in_collseq = find_collation_sequence_value (pin, elem_len); + } + /* match with range expression? */ + for (i = 0; i < cset->nranges; ++i) + if (cset->range_starts[i] <= in_collseq + && in_collseq <= cset->range_ends[i]) + { + match_len = elem_len; + goto check_node_accept_bytes_match; + } + + /* match with equivalence_class? */ + if (cset->nequiv_classes) + { + const unsigned char *cp = pin; + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + weights = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); + int32_t idx = findidx (&cp); + if (idx > 0) + for (i = 0; i < cset->nequiv_classes; ++i) + { + int32_t equiv_class_idx = cset->equiv_classes[i]; + size_t weight_len = weights[idx & 0xffffff]; + if (weight_len == weights[equiv_class_idx & 0xffffff] + && (idx >> 24) == (equiv_class_idx >> 24)) + { + int cnt = 0; + + idx &= 0xffffff; + equiv_class_idx &= 0xffffff; + + while (cnt <= weight_len + && (weights[equiv_class_idx + 1 + cnt] + == weights[idx + 1 + cnt])) + ++cnt; + if (cnt > weight_len) + { + match_len = elem_len; + goto check_node_accept_bytes_match; + } + } + } + } + } + else +# endif /* _LIBC */ + { + /* match with range expression? */ +#if __GNUC__ >= 2 + wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'}; +#else + wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; + cmp_buf[2] = wc; +#endif + for (i = 0; i < cset->nranges; ++i) + { + cmp_buf[0] = cset->range_starts[i]; + cmp_buf[4] = cset->range_ends[i]; + if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 + && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) + { + match_len = char_len; + goto check_node_accept_bytes_match; + } + } + } + check_node_accept_bytes_match: + if (!cset->non_match) + return match_len; + else + { + if (match_len > 0) + return 0; + else + return (elem_len > char_len) ? elem_len : char_len; + } + } + return 0; +} + +# ifdef _LIBC +static unsigned int +internal_function +find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) +{ + uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules == 0) + { + if (mbs_len == 1) + { + /* No valid character. Match it as a single byte character. */ + const unsigned char *collseq = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); + return collseq[mbs[0]]; + } + return UINT_MAX; + } + else + { + int32_t idx; + const unsigned char *extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); + int32_t extrasize = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra; + + for (idx = 0; idx < extrasize;) + { + int mbs_cnt, found = 0; + int32_t elem_mbs_len; + /* Skip the name of collating element name. */ + idx = idx + extra[idx] + 1; + elem_mbs_len = extra[idx++]; + if (mbs_len == elem_mbs_len) + { + for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt) + if (extra[idx + mbs_cnt] != mbs[mbs_cnt]) + break; + if (mbs_cnt == elem_mbs_len) + /* Found the entry. */ + found = 1; + } + /* Skip the byte sequence of the collating element. */ + idx += elem_mbs_len; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; + /* Skip the collation sequence value. */ + idx += sizeof (uint32_t); + /* Skip the wide char sequence of the collating element. */ + idx = idx + sizeof (uint32_t) * (extra[idx] + 1); + /* If we found the entry, return the sequence value. */ + if (found) + return *(uint32_t *) (extra + idx); + /* Skip the collation sequence value. */ + idx += sizeof (uint32_t); + } + return UINT_MAX; + } +} +# endif /* _LIBC */ +#endif /* RE_ENABLE_I18N */ + +/* Check whether the node accepts the byte which is IDX-th + byte of the INPUT. */ + +static int +internal_function +check_node_accept (const re_match_context_t *mctx, const re_token_t *node, + int idx) +{ + unsigned char ch; + ch = re_string_byte_at (&mctx->input, idx); + switch (node->type) + { + case CHARACTER: + if (node->opr.c != ch) + return 0; + break; + + case SIMPLE_BRACKET: + if (!bitset_contain (node->opr.sbcset, ch)) + return 0; + break; + +#ifdef RE_ENABLE_I18N + case OP_UTF8_PERIOD: + if (ch >= 0x80) + return 0; + /* FALLTHROUGH */ +#endif + case OP_PERIOD: + if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) + || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) + return 0; + break; + + default: + return 0; + } + + if (node->constraint) + { + /* The node has constraints. Check whether the current context + satisfies the constraints. */ + unsigned int context = re_string_context_at (&mctx->input, idx, + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) + return 0; + } + + return 1; +} + +/* Extend the buffers, if the buffers have run out. */ + +static reg_errcode_t +internal_function +extend_buffers (re_match_context_t *mctx) +{ + reg_errcode_t ret; + re_string_t *pstr = &mctx->input; + + /* Avoid overflow. */ + if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0)) + return REG_ESPACE; + + /* Double the lengthes of the buffers. */ + ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); + if (BE (ret != REG_NOERROR, 0)) + return ret; + + if (mctx->state_log != NULL) + { + /* And double the length of state_log. */ + /* XXX We have no indication of the size of this buffer. If this + allocation fail we have no indication that the state_log array + does not have the right size. */ + re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *, + pstr->bufs_len + 1); + if (BE (new_array == NULL, 0)) + return REG_ESPACE; + mctx->state_log = new_array; + } + + /* Then reconstruct the buffers. */ + if (pstr->icase) + { +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + ret = build_wcs_upper_buffer (pstr); + if (BE (ret != REG_NOERROR, 0)) + return ret; + } + else +#endif /* RE_ENABLE_I18N */ + build_upper_buffer (pstr); + } + else + { +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + build_wcs_buffer (pstr); + else +#endif /* RE_ENABLE_I18N */ + { + if (pstr->trans != NULL) + re_string_translate_buffer (pstr); + } + } + return REG_NOERROR; +} + + +/* Functions for matching context. */ + +/* Initialize MCTX. */ + +static reg_errcode_t +internal_function +match_ctx_init (re_match_context_t *mctx, int eflags, int n) +{ + mctx->eflags = eflags; + mctx->match_last = -1; + if (n > 0) + { + mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n); + mctx->sub_tops = re_malloc (re_sub_match_top_t *, n); + if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0)) + return REG_ESPACE; + } + /* Already zero-ed by the caller. + else + mctx->bkref_ents = NULL; + mctx->nbkref_ents = 0; + mctx->nsub_tops = 0; */ + mctx->abkref_ents = n; + mctx->max_mb_elem_len = 1; + mctx->asub_tops = n; + return REG_NOERROR; +} + +/* Clean the entries which depend on the current input in MCTX. + This function must be invoked when the matcher changes the start index + of the input, or changes the input string. */ + +static void +internal_function +match_ctx_clean (re_match_context_t *mctx) +{ + int st_idx; + for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) + { + int sl_idx; + re_sub_match_top_t *top = mctx->sub_tops[st_idx]; + for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) + { + re_sub_match_last_t *last = top->lasts[sl_idx]; + re_free (last->path.array); + re_free (last); + } + re_free (top->lasts); + if (top->path) + { + re_free (top->path->array); + re_free (top->path); + } + free (top); + } + + mctx->nsub_tops = 0; + mctx->nbkref_ents = 0; +} + +/* Free all the memory associated with MCTX. */ + +static void +internal_function +match_ctx_free (re_match_context_t *mctx) +{ + /* First, free all the memory associated with MCTX->SUB_TOPS. */ + match_ctx_clean (mctx); + re_free (mctx->sub_tops); + re_free (mctx->bkref_ents); +} + +/* Add a new backreference entry to MCTX. + Note that we assume that caller never call this function with duplicate + entry, and call with STR_IDX which isn't smaller than any existing entry. +*/ + +static reg_errcode_t +internal_function +match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from, + int to) +{ + if (mctx->nbkref_ents >= mctx->abkref_ents) + { + struct re_backref_cache_entry* new_entry; + new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry, + mctx->abkref_ents * 2); + if (BE (new_entry == NULL, 0)) + { + re_free (mctx->bkref_ents); + return REG_ESPACE; + } + mctx->bkref_ents = new_entry; + memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', + sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); + mctx->abkref_ents *= 2; + } + if (mctx->nbkref_ents > 0 + && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) + mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1; + + mctx->bkref_ents[mctx->nbkref_ents].node = node; + mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; + mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; + mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; + + /* This is a cache that saves negative results of check_dst_limits_calc_pos. + If bit N is clear, means that this entry won't epsilon-transition to + an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If + it is set, check_dst_limits_calc_pos_1 will recurse and try to find one + such node. + + A backreference does not epsilon-transition unless it is empty, so set + to all zeros if FROM != TO. */ + mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map + = (from == to ? ~0 : 0); + + mctx->bkref_ents[mctx->nbkref_ents++].more = 0; + if (mctx->max_mb_elem_len < to - from) + mctx->max_mb_elem_len = to - from; + return REG_NOERROR; +} + +/* Search for the first entry which has the same str_idx, or -1 if none is + found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ + +static int +internal_function +search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) +{ + int left, right, mid, last; + last = right = mctx->nbkref_ents; + for (left = 0; left < right;) + { + mid = (left + right) / 2; + if (mctx->bkref_ents[mid].str_idx < str_idx) + left = mid + 1; + else + right = mid; + } + if (left < last && mctx->bkref_ents[left].str_idx == str_idx) + return left; + else + return -1; +} + +/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches + at STR_IDX. */ + +static reg_errcode_t +internal_function +match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx) +{ +#ifdef DEBUG + assert (mctx->sub_tops != NULL); + assert (mctx->asub_tops > 0); +#endif + if (BE (mctx->nsub_tops == mctx->asub_tops, 0)) + { + int new_asub_tops = mctx->asub_tops * 2; + re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops, + re_sub_match_top_t *, + new_asub_tops); + if (BE (new_array == NULL, 0)) + return REG_ESPACE; + mctx->sub_tops = new_array; + mctx->asub_tops = new_asub_tops; + } + mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t)); + if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0)) + return REG_ESPACE; + mctx->sub_tops[mctx->nsub_tops]->node = node; + mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; + return REG_NOERROR; +} + +/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches + at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ + +static re_sub_match_last_t * +internal_function +match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx) +{ + re_sub_match_last_t *new_entry; + if (BE (subtop->nlasts == subtop->alasts, 0)) + { + int new_alasts = 2 * subtop->alasts + 1; + re_sub_match_last_t **new_array = re_realloc (subtop->lasts, + re_sub_match_last_t *, + new_alasts); + if (BE (new_array == NULL, 0)) + return NULL; + subtop->lasts = new_array; + subtop->alasts = new_alasts; + } + new_entry = calloc (1, sizeof (re_sub_match_last_t)); + if (BE (new_entry != NULL, 1)) + { + subtop->lasts[subtop->nlasts] = new_entry; + new_entry->node = node; + new_entry->str_idx = str_idx; + ++subtop->nlasts; + } + return new_entry; +} + +static void +internal_function +sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, + re_dfastate_t **limited_sts, int last_node, int last_str_idx) +{ + sctx->sifted_states = sifted_sts; + sctx->limited_states = limited_sts; + sctx->last_node = last_node; + sctx->last_str_idx = last_str_idx; + re_node_set_init_empty (&sctx->limits); +} From aa3f32d4806e46cb8cc8a49c5e27e2a01b91aa8d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1269/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 84261bba34..fa03ec4c96 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3835,6 +3835,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From e158a0648975b8888a885f92c893375bbbe84153 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1270/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index fa03ec4c96..33f2156fe7 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3850,7 +3850,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From ceed2f3fc951fcfb4dda238bbdcef8298b4806ff Mon Sep 17 00:00:00 2001 From: Nate Parsons Date: Fri, 10 Sep 2010 10:00:25 +0200 Subject: [PATCH 1271/3720] Fix compile for MinGW (continued) This fixes the fix in efe33c61(Fix compile error on MinGW). It only fixed things on one computer, but apparently not on others. The only difference between the declarations and function definitions here is the 'internal_function's. if _LIBC is not defined and __i386__ is, then this actually means something. [jes cobbled together the commit message and the commit from all over the place and cannot be held responsible for misrepresentations.] Signed-off-by: Johannes Schindelin --- compat/regex/regexec.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index aaf9c10cc3..f699b9375e 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -40,19 +40,24 @@ static reg_errcode_t re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, size_t nmatch, regmatch_t pmatch[], - int eflags); + int eflags) + internal_function; static int re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, - int stop, int ret_len); + int stop, int ret_len) + internal_function; static int re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, struct re_registers *regs, - int ret_len); + int ret_len) + internal_function; static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, - int nregs, int regs_allocated); -static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); + int nregs, int regs_allocated) + internal_function; +static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) + internal_function; static int check_matching (re_match_context_t *mctx, int fl_longest_match, int *p_match_first) internal_function; static int check_halt_state_context (const re_match_context_t *mctx, From 6b0c2e8b6693bd9305f6c27783f6db137751287e Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 20 Jul 2010 19:29:16 -0400 Subject: [PATCH 1272/3720] Side-step MSYS-specific path "corruption" leading to t5560 failure. Upon program invocation, MSYS converts environment variables containing path-like values from Unix-style to DOS-style under the assumption that the program being invoked understands only DOS-style pathnames. For instance, the Unix-style path /msysgit is translated to c:/msysgit. For test t5560, the path being requested from git-http-backend is specified via environment variable PATH_INFO as a URL path of the form /repo.git/foobar, which git-http-backend combines with GIT_PROJECT_ROOT to determine the actual physical path within the repository. This is a case where MSYS's conversion of the path-like value of PATH_INFO causes harm, for two reasons. First, the resulting converted path, when joined with GIT_PROJECT_ROOT is bogus (for instance, "C:/msysgit/git/t/trash-zzz/C:/msysgit/repo.git/HEAD"). Second, the converted PATH_INFO path is rejected by git-http-backend as an 'alias' due to validation failure on the part of daemon_avoid_alias(). Unfortunately, the standard work-around of doubling the leading slash (i.e. //repo.git/foobar) to suppress MSYS path conversion works only for command-line arguments, but not for environment variables. Consequently, side step the problem by instead passing git-http-backend an already-constructed full path rather than components GIT_PROJECT_ROOT and PATH_INFO. Signed-off-by: Eric Sunshine --- t/t5560-http-backend-noserver.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index 44885b850c..eb6f910e7a 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -8,8 +8,7 @@ HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ - GIT_PROJECT_ROOT="$HTTPD_DOCUMENT_ROOT_PATH" \ - PATH_INFO="${1%%\?*}" \ + PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%\?*}" \ git http-backend >act.out 2>act.err } From 22c0a2ff4e5795a90676eba658a5c45cafc6b851 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Sun, 12 Sep 2010 10:37:24 +0100 Subject: [PATCH 1273/3720] Do not strip CR when grepping HTTP headers. By default, MSYS grep reads in text-mode and converts CRLF into LF line endings. For testing HTTP use binary mode (-U) as checking is done for CR in HTTP headers Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t5560-http-backend-noserver.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index eb6f910e7a..406432e7a5 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -5,6 +5,8 @@ test_description='test git-http-backend-noserver' HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" +test_have_prereq MINGW && export GREP_OPTIONS=-U + run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ From 09457d28671e54015b6be308b5762fb207721dde Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Sat, 11 Sep 2010 23:10:57 +0200 Subject: [PATCH 1274/3720] log -L: do not free parents lists we might need again The parent rewriting code of 'git log -L' was too aggressive in freeing memory: assign_range_to_parent() will free the commit->parents field when it sees that a parent cannot pass off any blame (is a root commit in rewritten history). Its caller assign_parents_range() however will, upon finding the first parent that takes *full* blame for all ranges, rewind and reinstate all previous parents' line ranges and parent lists. This resurrects pointers to ranges that were freed in assign_range_to_parent() under some circumstances. Furthermore, we must not empty the parent lists either: the same rewind/reinstate code relies on them. Do both only if the commit was an ordinary (not merge or root) commit, in which case the merge code-path discussed here is never taken. Reported-by: Jonathan Nieder Signed-off-by: Thomas Rast Signed-off-by: Junio C Hamano --- line.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/line.c b/line.c index 63dd19a8c4..b0deafb70e 100644 --- a/line.c +++ b/line.c @@ -961,8 +961,10 @@ static int assign_range_to_parent(struct rev_info *rev, struct commit *c, * If there is no new ranges assigned to the parent, * we should mark it as a 'root' commit. */ - free(c->parents); - c->parents = NULL; + if (c->parents && !c->parents->next) { + free(c->parents); + c->parents = NULL; + } } /* and the ranges of current commit c is updated */ From 49389b6e5945e76799e53535bf50ec00cfcd5de9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 1275/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index d0be5aee72..00ad6cc0f0 100644 --- a/Makefile +++ b/Makefile @@ -1969,6 +1969,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1976,6 +1977,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From cab46f2a18e03c996048d9159ea1201b706764b5 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 1276/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 993a41a27ffe60f4b886709bce2b8a67775e3f5e Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1277/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From e4dfaaf3d0bde7066856b3c81a264c6a880165d3 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1278/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index d11f4c7a42..3d54f1c66d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 2ef2fa3a5e..283b412c83 100644 --- a/cache.h +++ b/cache.h @@ -552,6 +552,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f2d9e1fd97..9f6df8762d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 4b0a82040e..ab51e19a7b 100644 --- a/config.c +++ b/config.c @@ -643,6 +643,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 2d0c315379..763a4693cb 100644 --- a/environment.c +++ b/environment.c @@ -55,6 +55,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 81883e7270..26f7579dcb 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -514,4 +514,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From d1c0e0aed6f66cf159f0875395ce173c0c662d2e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1279/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 9f6df8762d..884f698873 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 93ad5eea10ecff1d45c736c8adc84881cc0188f4 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1280/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From e381e358bb6e9879e7b993102dfa5c6d5008e683 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 1281/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..1eaa83f686 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NONMINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NONMINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/test-lib.sh b/t/test-lib.sh index 830e5e7360..28ebb5f5fe 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -975,6 +975,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 66dca340fa5e6e533f44ac07b438066c885ffcfd Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1282/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index bb104895a9..76981e563d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1213,9 +1213,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2015,7 +2012,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2027,12 +2024,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2053,18 +2057,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2085,20 +2086,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From e2269d664b8403f8d1cafe48c2aa2f54ede6ef30 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1283/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 884f698873..208b9f987e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 928aae7529aa26198e01cd3dabe67e9f4dc3d1ca Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1284/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 208b9f987e..14be1bbb2e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1248,7 +1264,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 1f528310be0c0c7b2e426a8c3d4f1c0ac60fa17b Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1285/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 14be1bbb2e..d813203ea0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1305,6 +1358,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 23ba47788b06d87ff57233713ab2a0309b7e7463 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1286/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d813203ea0..ef23b6274e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 8180ecf924ccb52eeb9c2a428cb1a2134a557299 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1287/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 76981e563d..ccbed506ad 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 8f1a3e626d4ed352f44ff6795ea010f090d4346a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1288/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 4581c450ca7cd3d533a5b34db90ff6b7c4026618 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1289/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ef23b6274e..d770c2d00c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 6cbf413b6666c458ea488bb6188aef75ab80a317 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1290/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d770c2d00c..12f230b665 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1590,6 +1590,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1599,9 +1600,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From bbd411d64bd96a1e1873a7fc627f657ad850b241 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1291/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7fe8883ae0..28f67ce1d4 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -318,4 +318,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 28ebb5f5fe..3b8a0182a1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -970,6 +970,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 7185ae46e9684565faa7454a261f80c489f234cb Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1292/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 12f230b665..0c67afd55e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 4d59f2041a388f8c41449845bdd8b90412fdbb8b Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 1293/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0c67afd55e..2718b7d649 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 887effa218d6401a23ba54fa18b1b447b07ea58f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 1294/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..6b9f76a27d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From e417080d31a557cbc4ff12a89f7a8f40fa2435c9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1295/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 294584452b..3a18a3fd72 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -213,6 +213,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index c9300f3c8b..5cbde26ba6 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 76a87b63b81271e96abbf5e9339de702d4e7de7b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1296/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 3d54f1c66d..3204724939 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1613,6 +1613,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From dade7e95f656b12d12c11eaa3277ac083bdaca0c Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1297/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2718b7d649..62e7ba11ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 775287db401e85bcbc276658e948d40e286ee1af Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1298/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 47989fe6dd..544b614688 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1023,7 +1023,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From ecfa03414612cded7beec30a2107ae214e5e77fe Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1299/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 544b614688..2149b205de 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1109,7 +1109,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 1bc240bfe78aed9e5951c2048598b8b13b6b5616 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1300/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 62e7ba11ce..ec26ba6655 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From fa3210cb3b55085349a634b508b1e48e7ee58860 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1301/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index ec26ba6655..c058b22654 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1731,3 +1731,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index ab51e19a7b..d0d7f7e038 100644 --- a/config.c +++ b/config.c @@ -859,7 +859,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 26f7579dcb..008d922044 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -518,4 +518,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index a2c9d1e24a..30d66a94c0 100644 --- a/path.c +++ b/path.c @@ -353,7 +353,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From f9b210ac478c2d8a06ea2f9a2a0154a4fd3683e4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1302/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 3b8a0182a1..1fb4e175a3 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -870,6 +870,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 253b120577ec2c8708816b7fe1064582ed24e79a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1303/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 784eb8ca402fef4ffdc77e983aea7e0c2db463cf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1304/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From 1bde7878c9402ed206a458cddcbbd9eaf9c945f3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1305/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6b9f76a27d..ae9fc2346d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 1888e738196054d2262b8af31294b6b96ea32341 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1306/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 1fb4e175a3..fd32c03e81 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 91ac1210be825b759535969039e4ebabf56d7abd Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1307/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From efd50494cefabb4481dc5037a2c4de3264eaa1e7 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1308/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 283b412c83..102b11e1d6 100644 --- a/cache.h +++ b/cache.h @@ -721,7 +721,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index c058b22654..4dc751d047 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1749,3 +1749,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 008d922044..420cb84962 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -183,6 +183,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 30d66a94c0..0e560cabac 100644 --- a/path.c +++ b/path.c @@ -768,10 +768,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From cb756912b6777ed3dd0d44be463d3744f8d78167 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1309/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 124f1facde600b4480f38c30bade5fc25632c62c Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1310/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4dc751d047..f96d8367b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1752,23 +1752,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 50254cf20deab5d62b86e320f6d3921e87b909f4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 17:40:44 +0200 Subject: [PATCH 1311/3720] Make sure that git_getpass() never returns NULL The result of git_getpass() is used without checking for NULL, so let's just die() instead of returning NULL. Signed-off-by: Johannes Schindelin --- connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 3450cabd0e..57dc20c43c 100644 --- a/connect.c +++ b/connect.c @@ -631,8 +631,12 @@ char *git_getpass(const char *prompt) askpass = askpass_program; if (!askpass) askpass = getenv("SSH_ASKPASS"); - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; From 62f684c47e7e2ddc3f88788976f534e2910f83e2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1312/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ccbed506ad..8eeebe06e2 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1130,6 +1130,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From e690ffd6a59ceacec48c91ad09f647e436fb78a8 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1313/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 84301927e405acb62c7cd5f52ee103b274448832 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1314/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f96d8367b2..b0ad9192fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -701,11 +701,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 1987748e4e5b980d7eba865534f59501852df7bd Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1315/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 94416605aa83c46d89a1d12e19c314e8acd34d12 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1316/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From a2fffa3013f2adf3c7e59fbe9b51022daeb6a120 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1317/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From e3dd9fdea82902a9714f7bd6d22056432f0bb8f3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1318/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 21844685d3563aa1f12aa9e1d0b5b849deca0410 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Aug 2010 12:04:40 +0200 Subject: [PATCH 1319/3720] Fix typo in pack-objects' usage Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0e81673118..3756cf36ee 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -30,7 +30,7 @@ static const char pack_usage[] = " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n" " [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n" " [--reflog] [--stdout | base-name] [--include-tag]\n" - " [--keep-unreachable | --unpack-unreachable \n" + " [--keep-unreachable | --unpack-unreachable]\n" " [ Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1320/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a85e2f6319..7e6cff0448 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3834,6 +3834,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From b20bd05649e25ef7f4f136e354e4649a843118d8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1321/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7e6cff0448..ec0f17b463 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3849,7 +3849,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 7260aefbe10bdc0ea925a7bc93f2b32462f724c8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 26 Aug 2010 14:34:07 +0200 Subject: [PATCH 1322/3720] Fix compile error on MinGW The only difference between the declarations and function definitions here is the use of 'internal_function'. If _LIBC is not defined and __i386__ is, then this actually means something. Signed-off-by: Johannes Schindelin --- compat/regex/regexec.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index 0194965c5d..44f6fac724 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -40,19 +40,24 @@ static reg_errcode_t re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, size_t nmatch, regmatch_t pmatch[], - int eflags); + int eflags) + internal_function; static int re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, - int stop, int ret_len); + int stop, int ret_len) + internal_function; static int re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, struct re_registers *regs, - int ret_len); + int ret_len) + internal_function; static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, - int nregs, int regs_allocated); -static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); + int nregs, int regs_allocated) + internal_function; +static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) + internal_function; static int check_matching (re_match_context_t *mctx, int fl_longest_match, int *p_match_first) internal_function; static int check_halt_state_context (const re_match_context_t *mctx, @@ -353,6 +358,7 @@ weak_alias (__re_search_2, re_search_2) #endif static int +internal_function re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, @@ -397,6 +403,7 @@ re_search_2_stub (struct re_pattern_buffer *bufp, otherwise the position of the match is returned. */ static int +internal_function re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, @@ -484,6 +491,7 @@ re_search_stub (struct re_pattern_buffer *bufp, } static unsigned +internal_function re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs, int regs_allocated) @@ -614,6 +622,7 @@ re_exec (s) (START + RANGE >= 0 && START + RANGE <= LENGTH) */ static reg_errcode_t +internal_function re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, @@ -938,6 +947,7 @@ re_search_internal (const regex_t *preg, } static reg_errcode_t +internal_function prune_impossible_nodes (re_match_context_t *mctx) { const re_dfa_t *const dfa = mctx->dfa; From 0f83997995224fe7b0c9f5ca094409151a16b4b0 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 20 Jul 2010 19:29:16 -0400 Subject: [PATCH 1323/3720] Side-step MSYS-specific path "corruption" leading to t5560 failure. Upon program invocation, MSYS converts environment variables containing path-like values from Unix-style to DOS-style under the assumption that the program being invoked understands only DOS-style pathnames. For instance, the Unix-style path /msysgit is translated to c:/msysgit. For test t5560, the path being requested from git-http-backend is specified via environment variable PATH_INFO as a URL path of the form /repo.git/foobar, which git-http-backend combines with GIT_PROJECT_ROOT to determine the actual physical path within the repository. This is a case where MSYS's conversion of the path-like value of PATH_INFO causes harm, for two reasons. First, the resulting converted path, when joined with GIT_PROJECT_ROOT is bogus (for instance, "C:/msysgit/git/t/trash-zzz/C:/msysgit/repo.git/HEAD"). Second, the converted PATH_INFO path is rejected by git-http-backend as an 'alias' due to validation failure on the part of daemon_avoid_alias(). Unfortunately, the standard work-around of doubling the leading slash (i.e. //repo.git/foobar) to suppress MSYS path conversion works only for command-line arguments, but not for environment variables. Consequently, side step the problem by instead passing git-http-backend an already-constructed full path rather than components GIT_PROJECT_ROOT and PATH_INFO. Signed-off-by: Eric Sunshine --- t/t5560-http-backend-noserver.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index 44885b850c..eb6f910e7a 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -8,8 +8,7 @@ HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ - GIT_PROJECT_ROOT="$HTTPD_DOCUMENT_ROOT_PATH" \ - PATH_INFO="${1%%\?*}" \ + PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%\?*}" \ git http-backend >act.out 2>act.err } From 0c19e93b9cde27e195ed427aafe8ae9e48448e98 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Sun, 12 Sep 2010 10:37:24 +0100 Subject: [PATCH 1324/3720] Do not strip CR when grepping HTTP headers. By default, MSYS grep reads in text-mode and converts CRLF into LF line endings. For testing HTTP use binary mode (-U) as checking is done for CR in HTTP headers Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t5560-http-backend-noserver.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index eb6f910e7a..406432e7a5 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -5,6 +5,8 @@ test_description='test git-http-backend-noserver' HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" +test_have_prereq MINGW && export GREP_OPTIONS=-U + run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ From 542a731491e4f4303d982ad9db8b4ed258ed599b Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Fri, 17 Sep 2010 14:27:56 +0100 Subject: [PATCH 1325/3720] Skip 'git archive --remote' test on msysGit This test requires git daemon support which is not available on msysgit Signed-off-by: Pat Thoyts --- t/t5000-tar-tree.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 27bfba55bd..bc87939957 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -94,7 +94,7 @@ test_expect_success 'git archive with --output' \ 'git archive --output=b4.tar HEAD && test_cmp b.tar b4.tar' -test_expect_success 'git archive --remote' \ +test_expect_success NONMINGW 'git archive --remote' \ 'git archive --remote=. HEAD >b5.tar && test_cmp b.tar b5.tar' From da0b3d22be30b354f59026db8920b59b9ddc807b Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Fri, 17 Sep 2010 09:16:01 -0400 Subject: [PATCH 1326/3720] Side-step sed line-ending "corruption" leading to t6038 failure. By default, MSYS sed throws away CR from CRLF line-endings. Tests t6038.5 and t6038.6 employ sed to normalize conflict output of git-merge for validation purposes. These tests expect CRLF line-endings to be present in the normalized output of git-merge, and thus fail when sed undesirably removes CR. Fix by employing sed's -b/--binary switch to suppress its default behavior of dropping CR characters. Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t6038-merge-text-auto.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh index 52d0dc4bb8..460bf741b5 100755 --- a/t/t6038-merge-text-auto.sh +++ b/t/t6038-merge-text-auto.sh @@ -14,6 +14,8 @@ test_description='CRLF merge conflict across text=auto change . ./test-lib.sh +test_have_prereq MINGW && SED_OPTIONS=-b + test_expect_success setup ' git config core.autocrlf false && @@ -60,7 +62,7 @@ test_expect_success setup ' test_expect_success 'set up fuzz_conflict() helper' ' fuzz_conflict() { - sed -e "s/^\([<>=]......\) .*/\1/" "$@" + sed $SED_OPTIONS -e "s/^\([<>=]......\) .*/\1/" "$@" } ' From 784fd5e7af07e5ca5b45b63b35c03039dbc61518 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 1327/3720] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index d0be5aee72..00ad6cc0f0 100644 --- a/Makefile +++ b/Makefile @@ -1969,6 +1969,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1976,6 +1977,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 13c3ff9519fef26ddf7aba14c3db3ceb28dcd0f0 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 1328/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From fb33a74dc3d910c9c25a6c56d69189bd9a3d0b7e Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1329/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 38d839b2e80f7d1ca507d5853ba61ea8775ee42f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1330/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index d11f4c7a42..3d54f1c66d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 2ef2fa3a5e..283b412c83 100644 --- a/cache.h +++ b/cache.h @@ -552,6 +552,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f2d9e1fd97..9f6df8762d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..7bbef44210 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -280,6 +277,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 4b0a82040e..ab51e19a7b 100644 --- a/config.c +++ b/config.c @@ -643,6 +643,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 2d0c315379..763a4693cb 100644 --- a/environment.c +++ b/environment.c @@ -55,6 +55,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 81883e7270..26f7579dcb 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -514,4 +514,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From b46d1f6fdda0fb5fd91f87ad2bbac7f29244dd5a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1331/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 9f6df8762d..884f698873 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From ece38054c9923fa27dbbe8813314dfde7a5e5514 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1332/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 7096283fca0a8e319f084eedd2696d47489fe728 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 1333/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..1eaa83f686 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NONMINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NONMINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/test-lib.sh b/t/test-lib.sh index 830e5e7360..28ebb5f5fe 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -975,6 +975,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 3150e566b9aa00b0ac651eaed4752362b971dd38 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1334/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 4617f29c26..cb594fe019 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1226,9 +1226,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2028,7 +2025,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2040,12 +2037,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2066,18 +2070,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2098,20 +2099,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 73d1f2d5b22c39a0ddeb5391859d5c59a68636c7 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1335/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 884f698873..208b9f987e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 7bbef44210..0f894c7f26 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 189fa92929494a61b9dc25c449331f4bbd157bbd Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1336/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 208b9f987e..14be1bbb2e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1248,7 +1264,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 2bc740a12a6c60f69691aa8739075c585c6990ef Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1337/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 14be1bbb2e..d813203ea0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1305,6 +1358,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 2fe90c25bdbbd626ba951f1116e35282b5f42cdf Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1338/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d813203ea0..ef23b6274e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 0f894c7f26..8a4f38e7d3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 485a50819150b84979605028a45c2780e4591887 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1339/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cb594fe019..0d36b56d18 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1143,6 +1143,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 05cac183f59a524fccc7a20deb6ce82bf8c038d1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1340/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From fb2eae98355f87b18b7d16026823ab8854cf6beb Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1341/3720] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ef23b6274e..d770c2d00c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -360,8 +360,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -377,6 +380,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -388,12 +411,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -412,7 +435,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 8a4f38e7d3..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -230,10 +230,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 74187e915127290d116cbc3f3bcc5a146e019be6 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1342/3720] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d770c2d00c..12f230b665 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1590,6 +1590,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1599,9 +1600,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From ca08398542e744b29e050b7be21b4351b4b88010 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1343/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7fe8883ae0..28f67ce1d4 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -318,4 +318,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 28ebb5f5fe..3b8a0182a1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -970,6 +970,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 239fafd45e97285ededa11d26a0ba345d093789f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1344/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 12f230b665..0c67afd55e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 85240f54616ff58c7fadfd93254e3d9f3f0d3bd1 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 1345/3720] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0c67afd55e..2718b7d649 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -390,7 +390,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 9d51925c5a72dbc1cce34d2acfe608f522cb6601 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 1346/3720] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..6b9f76a27d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -445,7 +445,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 096f679b437b047d9640af92df1a961eacf69404 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1347/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 294584452b..3a18a3fd72 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -213,6 +213,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index c9300f3c8b..5cbde26ba6 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From db906cd714c492e3ed29ddfc4fc37103f5ea6e76 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1348/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 3d54f1c66d..3204724939 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1613,6 +1613,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 783f6398c75fed3ba63acfab98126a3e760d0345 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1349/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2718b7d649..62e7ba11ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From eda4e1f0cc85f02ddcbb14ec83d69927801df2b3 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1350/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 8dbd80aaa5..5f2dfb7929 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1037,7 +1037,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 42b0b0f338ecf37a6ba45abd3bc9bae134141f1c Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1351/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 5f2dfb7929..6c97935f30 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1123,7 +1123,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 769936940751c86321c691f53adb5c72f3cdc551 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1352/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 62e7ba11ce..ec26ba6655 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 31b96ca5c0bc2f3d5f36f8e1dde698dde8c5d608 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1353/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index ec26ba6655..c058b22654 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1731,3 +1731,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index ab51e19a7b..d0d7f7e038 100644 --- a/config.c +++ b/config.c @@ -859,7 +859,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 26f7579dcb..008d922044 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -518,4 +518,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index a2c9d1e24a..30d66a94c0 100644 --- a/path.c +++ b/path.c @@ -353,7 +353,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 8ae74eb3b81349399ce2fe9ae2f33bec2f0fdfb5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1354/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 3b8a0182a1..1fb4e175a3 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -870,6 +870,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From a99f0360e4f9381d5b6623bb42046faadddd180e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1355/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From f0aa451bc374baca7641d902e56898d6e9d206fe Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1356/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. Signed-off-by: Johannes Schindelin --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..9c5bc2dfb8 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From 9710a650a9d97a049b2e8e8437ad113f39f76929 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1357/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6b9f76a27d..ae9fc2346d 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From d5e570eedba4e6fc2334cfa644717c072979b310 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1358/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 1fb4e175a3..fd32c03e81 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 1744e90acce069233cdbcdb36390e76b059bf6bb Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1359/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From 34e0dfd7c33e8c6314a9480a3810342db9f17324 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1360/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 283b412c83..102b11e1d6 100644 --- a/cache.h +++ b/cache.h @@ -721,7 +721,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index c058b22654..4dc751d047 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1749,3 +1749,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 008d922044..420cb84962 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -183,6 +183,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 30d66a94c0..0e560cabac 100644 --- a/path.c +++ b/path.c @@ -768,10 +768,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 18d6e75843ec006bb0bd30faf61027b398e16406 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1361/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 05a5eb94989fe50682dd3abf10ba3671e0ee7513 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1362/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4dc751d047..f96d8367b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1752,23 +1752,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 8fe759ee4f074d5fc233c348a54724af1867bc5b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 17:40:44 +0200 Subject: [PATCH 1363/3720] Make sure that git_getpass() never returns NULL The result of git_getpass() is used without checking for NULL, so let's just die() instead of returning NULL. Signed-off-by: Johannes Schindelin --- connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 3450cabd0e..57dc20c43c 100644 --- a/connect.c +++ b/connect.c @@ -631,8 +631,12 @@ char *git_getpass(const char *prompt) askpass = askpass_program; if (!askpass) askpass = getenv("SSH_ASKPASS"); - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; From 682bf55e3af92bab57caea8daf15947d09da88b9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1364/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0d36b56d18..3c9a8aad91 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1143,6 +1143,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 71f29474aad53971da1dd8a76ed8098216908988 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1365/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From e38a3894c497cd65750473055493204358624c36 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1366/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f96d8367b2..b0ad9192fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -701,11 +701,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 928579782e73c0b38db9fae944606d5b19f894ed Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1367/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 432d94ff323b5ac82288d25c4cb5cbfc492606cb Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1368/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 8f4d451e01659feb78fff1c006e85c107929e5a0 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1369/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From 43388422700e805feed5f099b8007b7fdefc6975 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1370/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 62a48cc9c2fa14ff8fef45fb61e331732e6fddd4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Aug 2010 12:04:40 +0200 Subject: [PATCH 1371/3720] Fix typo in pack-objects' usage Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0e81673118..3756cf36ee 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -30,7 +30,7 @@ static const char pack_usage[] = " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n" " [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n" " [--reflog] [--stdout | base-name] [--include-tag]\n" - " [--keep-unreachable | --unpack-unreachable \n" + " [--keep-unreachable | --unpack-unreachable]\n" " [ Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1372/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a85e2f6319..7e6cff0448 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3834,6 +3834,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 695121fd4066bfe925116b11f05d82ed8531e23f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1373/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7e6cff0448..ec0f17b463 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3849,7 +3849,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From f51763461658da7c03fb465bf91d7c941f2223f4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 26 Aug 2010 14:34:07 +0200 Subject: [PATCH 1374/3720] Fix compile error on MinGW The only difference between the declarations and function definitions here is the use of 'internal_function'. If _LIBC is not defined and __i386__ is, then this actually means something. Signed-off-by: Johannes Schindelin --- compat/regex/regexec.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index 0194965c5d..44f6fac724 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -40,19 +40,24 @@ static reg_errcode_t re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, size_t nmatch, regmatch_t pmatch[], - int eflags); + int eflags) + internal_function; static int re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, - int stop, int ret_len); + int stop, int ret_len) + internal_function; static int re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, struct re_registers *regs, - int ret_len); + int ret_len) + internal_function; static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, - int nregs, int regs_allocated); -static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); + int nregs, int regs_allocated) + internal_function; +static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) + internal_function; static int check_matching (re_match_context_t *mctx, int fl_longest_match, int *p_match_first) internal_function; static int check_halt_state_context (const re_match_context_t *mctx, @@ -353,6 +358,7 @@ weak_alias (__re_search_2, re_search_2) #endif static int +internal_function re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, @@ -397,6 +403,7 @@ re_search_2_stub (struct re_pattern_buffer *bufp, otherwise the position of the match is returned. */ static int +internal_function re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, @@ -484,6 +491,7 @@ re_search_stub (struct re_pattern_buffer *bufp, } static unsigned +internal_function re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs, int regs_allocated) @@ -614,6 +622,7 @@ re_exec (s) (START + RANGE >= 0 && START + RANGE <= LENGTH) */ static reg_errcode_t +internal_function re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, @@ -938,6 +947,7 @@ re_search_internal (const regex_t *preg, } static reg_errcode_t +internal_function prune_impossible_nodes (re_match_context_t *mctx) { const re_dfa_t *const dfa = mctx->dfa; From be9ec6209cf418ce0c5ba52fa52214d7704f2037 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 20 Jul 2010 19:29:16 -0400 Subject: [PATCH 1375/3720] Side-step MSYS-specific path "corruption" leading to t5560 failure. Upon program invocation, MSYS converts environment variables containing path-like values from Unix-style to DOS-style under the assumption that the program being invoked understands only DOS-style pathnames. For instance, the Unix-style path /msysgit is translated to c:/msysgit. For test t5560, the path being requested from git-http-backend is specified via environment variable PATH_INFO as a URL path of the form /repo.git/foobar, which git-http-backend combines with GIT_PROJECT_ROOT to determine the actual physical path within the repository. This is a case where MSYS's conversion of the path-like value of PATH_INFO causes harm, for two reasons. First, the resulting converted path, when joined with GIT_PROJECT_ROOT is bogus (for instance, "C:/msysgit/git/t/trash-zzz/C:/msysgit/repo.git/HEAD"). Second, the converted PATH_INFO path is rejected by git-http-backend as an 'alias' due to validation failure on the part of daemon_avoid_alias(). Unfortunately, the standard work-around of doubling the leading slash (i.e. //repo.git/foobar) to suppress MSYS path conversion works only for command-line arguments, but not for environment variables. Consequently, side step the problem by instead passing git-http-backend an already-constructed full path rather than components GIT_PROJECT_ROOT and PATH_INFO. Signed-off-by: Eric Sunshine --- t/t5560-http-backend-noserver.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index 44885b850c..eb6f910e7a 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -8,8 +8,7 @@ HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ - GIT_PROJECT_ROOT="$HTTPD_DOCUMENT_ROOT_PATH" \ - PATH_INFO="${1%%\?*}" \ + PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%\?*}" \ git http-backend >act.out 2>act.err } From 69cc8e35efc64fc7e8146c0dd712ec20da8cb68f Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Sun, 12 Sep 2010 10:37:24 +0100 Subject: [PATCH 1376/3720] Do not strip CR when grepping HTTP headers. By default, MSYS grep reads in text-mode and converts CRLF into LF line endings. For testing HTTP use binary mode (-U) as checking is done for CR in HTTP headers Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t5560-http-backend-noserver.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index eb6f910e7a..406432e7a5 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -5,6 +5,8 @@ test_description='test git-http-backend-noserver' HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" +test_have_prereq MINGW && export GREP_OPTIONS=-U + run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ From 90a513606997be42ef5b0451a20598a8f4b68298 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Fri, 17 Sep 2010 14:27:56 +0100 Subject: [PATCH 1377/3720] Skip 'git archive --remote' test on msysGit This test requires git daemon support which is not available on msysgit Signed-off-by: Pat Thoyts --- t/t5000-tar-tree.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 27bfba55bd..bc87939957 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -94,7 +94,7 @@ test_expect_success 'git archive with --output' \ 'git archive --output=b4.tar HEAD && test_cmp b.tar b4.tar' -test_expect_success 'git archive --remote' \ +test_expect_success NONMINGW 'git archive --remote' \ 'git archive --remote=. HEAD >b5.tar && test_cmp b.tar b5.tar' From 84538751a19e001b281a06829226b3d16af40844 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Fri, 17 Sep 2010 09:16:01 -0400 Subject: [PATCH 1378/3720] Side-step sed line-ending "corruption" leading to t6038 failure. By default, MSYS sed throws away CR from CRLF line-endings. Tests t6038.5 and t6038.6 employ sed to normalize conflict output of git-merge for validation purposes. These tests expect CRLF line-endings to be present in the normalized output of git-merge, and thus fail when sed undesirably removes CR. Fix by employing sed's -b/--binary switch to suppress its default behavior of dropping CR characters. Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t6038-merge-text-auto.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh index 52d0dc4bb8..460bf741b5 100755 --- a/t/t6038-merge-text-auto.sh +++ b/t/t6038-merge-text-auto.sh @@ -14,6 +14,8 @@ test_description='CRLF merge conflict across text=auto change . ./test-lib.sh +test_have_prereq MINGW && SED_OPTIONS=-b + test_expect_success setup ' git config core.autocrlf false && @@ -60,7 +62,7 @@ test_expect_success setup ' test_expect_success 'set up fuzz_conflict() helper' ' fuzz_conflict() { - sed -e "s/^\([<>=]......\) .*/\1/" "$@" + sed $SED_OPTIONS -e "s/^\([<>=]......\) .*/\1/" "$@" } ' From 351dbaeff9d2b51ab0732cf00ce174e7dff85c88 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 23 Sep 2010 17:35:25 +0000 Subject: [PATCH 1379/3720] mingw: do not crash on open(NULL, ...) fetch_and_setup_pack_index() apparently pass a NULL-pointer to parse_pack_index(), which in turn pass it to check_packed_git_idx(), which again pass it to open(). Since open() already sets errno correctly for the NULL-case, let's just avoid the problematic strcmp. Acked-by: Johannes Sixt Signed-off-by: Erik Faye-Lund Signed-off-by: Pat Thoyts --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index b0ad9192fb..b408c3c161 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -297,7 +297,7 @@ int mingw_open (const char *filename, int oflags, ...) mode = va_arg(args, int); va_end(args); - if (!strcmp(filename, "/dev/null")) + if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; fd = open(filename, oflags, mode); From 37ddb94627978459f3a8d2025d3a35957a24828b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1380/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 0a5011f615..6490206411 100644 --- a/http.c +++ b/http.c @@ -2,6 +2,7 @@ #include "pack.h" #include "sideband.h" #include "run-command.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -137,6 +138,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -144,17 +157,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 59ae364ca59eb7f3923211fe564e3d8e4ca5021f Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Mon, 27 Sep 2010 07:01:59 -0400 Subject: [PATCH 1381/3720] Fix Windows-specific macro redefinition warning. shell.c defines macro HELP_COMMAND which collides with a like-named macro from winuser.h. Avoid collision by sanitizing preprocessor namespace after including Windows headers. Acked-by: Johannes Schindelin Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 849f37c02b..be6e80fc05 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -78,6 +78,12 @@ struct itimerval { }; #define ITIMER_REAL 0 +/* + * sanitize preprocessor namespace polluted by Windows headers defining + * macros which collide with git local versions + */ +#undef HELP_COMMAND /* from winuser.h */ + /* * trivial stubs */ From 494ad365c726f3d2474688a1edd4bc7ef8c999ca Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Mon, 27 Sep 2010 07:02:17 -0400 Subject: [PATCH 1382/3720] Add MinGW-specific execv() override. As of 2dbc887e, shell.c employs execv(), so provide a MinGW-specific mingw_execv() override, complementing existing mingw_execvp() and cousins. As a bonus, this also resolves a compilation warning due to an execv() prototype mismatch between Linux and MinGW. Linux expects the second argument to be (char *const *), whereas MinGW expects (const char *const *). Acked-by: Johannes Schindelin Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- compat/mingw.c | 5 +++++ compat/mingw.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index b408c3c161..2fbe381315 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1106,6 +1106,11 @@ void mingw_execvp(const char *cmd, char *const *argv) free_path_split(path); } +void mingw_execv(const char *cmd, char *const *argv) +{ + mingw_execve(cmd, argv, environ); +} + static char **copy_environ(void) { char **env; diff --git a/compat/mingw.h b/compat/mingw.h index be6e80fc05..5587d140a8 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -251,6 +251,8 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env, int fhin, int fhout, int fherr); void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp +void mingw_execv(const char *cmd, char *const *argv); +#define execv mingw_execv static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); } From b27be680552ca5fd9e4cf92b638b01c13f4da953 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Mon, 27 Sep 2010 08:01:35 -0400 Subject: [PATCH 1383/3720] Side-step line-ending corruption leading to t3032 failures. By default, MSYS grep and sed throw away CR from CRLF line-endings. Tests t3032.4 through t3032.8 employ grep and fail due to this behavior. Test t3032.9 employs sed and fails. Fix by employing grep's -U/--binary and sed's -b/--binary switches to suppress the default behavior of dropping CR characters. Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t3032-merge-recursive-options.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh index 2293797553..03ea961720 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-options.sh @@ -13,9 +13,14 @@ test_description='merge-recursive options . ./test-lib.sh +if test_have_prereq MINGW; then + export GREP_OPTIONS=-U + SED_OPTIONS=-b +fi + test_expect_success 'setup' ' conflict_hunks () { - sed -n -e " + sed $SED_OPTIONS -n -e " /^<<< Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 1384/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 21ed8a9000491d0d7d1249ec0f3c20a0e6585378 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1385/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 46fcbec32718cab4e0ef2b1a116c02d2834b576f Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1386/3720] MinGW: fix stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Includes squashed fix st_mode for symlink dirs Signed-off-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 39 +++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f2d9e1fd97..ee8f3be5b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -192,8 +192,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -209,6 +212,25 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -220,12 +242,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -244,7 +266,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..47839663be 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -235,10 +235,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 84329f64e5bda0eaec015a75a39c86e02221a3ac Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1387/3720] MinGW: Report errors when failing to launch the html browser. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ee8f3be5b2..431e32265d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1417,6 +1417,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1426,9 +1427,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From bb86711f5f6032862d06b8ab8b382c9869a1013e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1388/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. [PT: fixed typo in the char range noted by junio] Signed-off-by: Johannes Schindelin Signed-off-by: Pat Thoyts --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..8643f74cb0 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-Z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From e4ed1a7eac31d8ec8cc0ce7be3445454589dcb4d Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 27 Sep 2010 22:02:57 +0100 Subject: [PATCH 1389/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Moves the NOT_MINGW prereq from t5503 into the test library. Signed-off-by: Pat Thoyts --- t/t1300-repo-config.sh | 6 +++--- t/t5503-tagfollow.sh | 9 ++------- t/test-lib.sh | 1 + 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..d0ab8ffe1b 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NOT_MINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NOT_MINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NOT_MINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 8a298a655f..b6b1fc30cd 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -4,14 +4,9 @@ test_description='test automatic tag following' . ./test-lib.sh -case $(uname -s) in -*MINGW*) +if !test_have_prereq NOT_MINGW; then say "GIT_DEBUG_SEND_PACK not supported - skipping tests" - ;; -*) - test_set_prereq NOT_MINGW - ;; -esac +fi # End state of the repository: # diff --git a/t/test-lib.sh b/t/test-lib.sh index 830e5e7360..a85e7954ad 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -975,6 +975,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NOT_MINGW ;; esac From aa5069aa0648ecd5ffb527e31aaabb50785602d5 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Sun, 12 Sep 2010 10:37:24 +0100 Subject: [PATCH 1390/3720] Do not strip CR when grepping HTTP headers. By default, MSYS grep reads in text-mode and converts CRLF into LF line endings. For testing HTTP use binary mode (-U) as checking is done for CR in HTTP headers Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t5560-http-backend-noserver.sh | 2 ++ t/test-lib.sh | 1 + 2 files changed, 3 insertions(+) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index 44885b850c..4b0364374d 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -5,6 +5,8 @@ test_description='test git-http-backend-noserver' HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" +test_have_prereq MINGW && export GREP_OPTIONS=-U + run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ diff --git a/t/test-lib.sh b/t/test-lib.sh index a85e7954ad..2af8f10c83 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -970,6 +970,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 02ecf31a7be675afc4ab1b934f32cab99f4532ef Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Fri, 17 Sep 2010 14:27:56 +0100 Subject: [PATCH 1391/3720] Skip 'git archive --remote' test on msysGit This test requires git daemon support which is not available on msysgit Signed-off-by: Pat Thoyts --- t/t5000-tar-tree.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 27bfba55bd..cff1b3e050 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -94,7 +94,7 @@ test_expect_success 'git archive with --output' \ 'git archive --output=b4.tar HEAD && test_cmp b.tar b4.tar' -test_expect_success 'git archive --remote' \ +test_expect_success NOT_MINGW 'git archive --remote' \ 'git archive --remote=. HEAD >b5.tar && test_cmp b.tar b5.tar' From ef5f967b0cbba9407c9b1031881676db6d1a462b Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Fri, 17 Sep 2010 09:16:01 -0400 Subject: [PATCH 1392/3720] Side-step sed line-ending "corruption" leading to t6038 failure. By default, MSYS sed throws away CR from CRLF line-endings. Tests t6038.5 and t6038.6 employ sed to normalize conflict output of git-merge for validation purposes. These tests expect CRLF line-endings to be present in the normalized output of git-merge, and thus fail when sed undesirably removes CR. Fix by employing sed's -b/--binary switch to suppress its default behavior of dropping CR characters. Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t6038-merge-text-auto.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh index 52d0dc4bb8..460bf741b5 100755 --- a/t/t6038-merge-text-auto.sh +++ b/t/t6038-merge-text-auto.sh @@ -14,6 +14,8 @@ test_description='CRLF merge conflict across text=auto change . ./test-lib.sh +test_have_prereq MINGW && SED_OPTIONS=-b + test_expect_success setup ' git config core.autocrlf false && @@ -60,7 +62,7 @@ test_expect_success setup ' test_expect_success 'set up fuzz_conflict() helper' ' fuzz_conflict() { - sed -e "s/^\([<>=]......\) .*/\1/" "$@" + sed $SED_OPTIONS -e "s/^\([<>=]......\) .*/\1/" "$@" } ' From 0f5f51c8fb2804ada6ce41213424cda163db2839 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 20 Jul 2010 19:29:16 -0400 Subject: [PATCH 1393/3720] Side-step MSYS-specific path "corruption" leading to t5560 failure. Upon program invocation, MSYS converts environment variables containing path-like values from Unix-style to DOS-style under the assumption that the program being invoked understands only DOS-style pathnames. For instance, the Unix-style path /msysgit is translated to c:/msysgit. For test t5560, the path being requested from git-http-backend is specified via environment variable PATH_INFO as a URL path of the form /repo.git/foobar, which git-http-backend combines with GIT_PROJECT_ROOT to determine the actual physical path within the repository. This is a case where MSYS's conversion of the path-like value of PATH_INFO causes harm, for two reasons. First, the resulting converted path, when joined with GIT_PROJECT_ROOT is bogus (for instance, "C:/msysgit/git/t/trash-zzz/C:/msysgit/repo.git/HEAD"). Second, the converted PATH_INFO path is rejected by git-http-backend as an 'alias' due to validation failure on the part of daemon_avoid_alias(). Unfortunately, the standard work-around of doubling the leading slash (i.e. //repo.git/foobar) to suppress MSYS path conversion works only for command-line arguments, but not for environment variables. Consequently, side step the problem by instead passing git-http-backend an already-constructed full path rather than components GIT_PROJECT_ROOT and PATH_INFO. Signed-off-by: Eric Sunshine --- t/t5560-http-backend-noserver.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index 4b0364374d..406432e7a5 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -10,8 +10,7 @@ test_have_prereq MINGW && export GREP_OPTIONS=-U run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ - GIT_PROJECT_ROOT="$HTTPD_DOCUMENT_ROOT_PATH" \ - PATH_INFO="${1%%\?*}" \ + PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%\?*}" \ git http-backend >act.out 2>act.err } From 9e480700345441ebe146f0d9b86a297b2020ea4e Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 30 Sep 2010 14:24:07 +0100 Subject: [PATCH 1394/3720] git-am: fix detection of absolute paths for windows Add an is_absolute_path function to abstract out platform differences in checking for an absolute or relative path. Specifically fixes t4150-am on Windows. [PT: updated following suggestion from j6t to support \* and //*] Signed-off-by: Johannes Sixt Signed-off-by: Pat Thoyts --- git-am.sh | 12 ++++++------ git-sh-setup.sh | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/git-am.sh b/git-am.sh index e7f008c7ba..9317b38935 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,12 +444,12 @@ else set x first= } - case "$arg" in - /*) - set "$@" "$arg" ;; - *) - set "$@" "$prefix$arg" ;; - esac + if is_absolute_path "$arg" + then + set "$@" "$arg" + else + set "$@" "$prefix$arg" + fi done shift fi diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 6131670860..58d30c9388 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -209,5 +209,20 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + is_absolute_path () { + case "$1" in + [/\\]* | [A-Za-z]:*) + return 0 ;; + esac + return 1 + } ;; +*) + is_absolute_path () { + case "$1" in + /*) + return 0 ;; + esac + return 1 + } esac From 0a0c4aa6b74647bfffce7db44333dc173a8c119a Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 23 Sep 2010 17:35:25 +0000 Subject: [PATCH 1395/3720] mingw: do not crash on open(NULL, ...) fetch_and_setup_pack_index() apparently pass a NULL-pointer to parse_pack_index(), which in turn pass it to check_packed_git_idx(), which again pass it to open(). Since open() already sets errno correctly for the NULL-case, let's just avoid the problematic strcmp. [PT: squashed in fix for freopen which was missed first time round] Acked-by: Johannes Sixt Signed-off-by: Erik Faye-Lund Signed-off-by: Pat Thoyts --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 431e32265d..bd1403a1d5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -127,7 +127,7 @@ int mingw_open (const char *filename, int oflags, ...) mode = va_arg(args, int); va_end(args); - if (!strcmp(filename, "/dev/null")) + if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; fd = open(filename, oflags, mode); @@ -160,7 +160,7 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { - if (!strcmp(filename, "/dev/null")) + if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; return fopen(filename, otype); } From 845882dec595bc34eaacd81c71750a4e14235a7a Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1396/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index d82c0da2cf..f81cddb6b9 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..ea6ea8b431 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 2ef2fa3a5e..283b412c83 100644 --- a/cache.h +++ b/cache.h @@ -552,6 +552,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index bd1403a1d5..710150f442 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 47839663be..56e58ba341 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -281,6 +278,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 4b0a82040e..ab51e19a7b 100644 --- a/config.c +++ b/config.c @@ -643,6 +643,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 2d0c315379..763a4693cb 100644 --- a/environment.c +++ b/environment.c @@ -55,6 +55,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 81883e7270..26f7579dcb 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -514,4 +514,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From a273508993028ebae47cc7dd110627bdba48806e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1397/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 710150f442..98163da387 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From bb54a12f95245a767809c6575e0e9286ff6514e9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1398/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From e6684923cf00f05d900d94af6fed4f1bb63cb9f7 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1399/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 4617f29c26..cb594fe019 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1226,9 +1226,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2028,7 +2025,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2040,12 +2037,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2066,18 +2070,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2098,20 +2099,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From cd6cccd7a1c11f925f6b1f3b820f97f950c0361d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1400/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 98163da387..49c594f29c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 56e58ba341..220ae907cd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 21eeb3f7f17bd70b3b3495abed1824276c3802d9 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1401/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 49c594f29c..4b40c6f4e4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1279,7 +1295,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 8ee4074bc04adf64bb4c4b01228d272bde4ce174 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1402/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4b40c6f4e4..601656cff0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1336,6 +1389,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From b8cd1cdaadfa6cc0111ed8f3b3fecad7e7d6fb82 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1403/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 601656cff0..2443bc4746 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 220ae907cd..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From afc06b06c26b187f84950c84a6ef2ff05fed309d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1404/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cb594fe019..0d36b56d18 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1143,6 +1143,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 01d00e7a70c0fb3f353bdf9e5a7bd40d012074b5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1405/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 3131bd5011d152f1f60c56115d93e0387a122e63 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1406/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7fe8883ae0..28f67ce1d4 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -318,4 +318,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 7857d06e5908bc19e9b123a41813871339dd0708 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1407/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2443bc4746..01ae468579 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 8139a1ffeec5c5868d69a34b26b1458d6581e1eb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1408/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 294584452b..3a18a3fd72 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -213,6 +213,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index c9300f3c8b..5cbde26ba6 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 4cdf3c10c5eb266ef0eaf68396b6fcb536e4e6ff Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1409/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f81cddb6b9..02cc2cc98c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1607,6 +1607,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 61f6dbb99c19cce8938c6e42e77ff7a114d47543 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1410/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 01ae468579..8258094799 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 7061c65bd96fb24d44bce256959e78cae0e238d2 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1411/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index e1f29a72a1..15e63df59e 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1017,7 +1017,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 68ee5fab35b80c0db2657a84d3bb457a7f31549f Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1412/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 15e63df59e..eee1a8fe3d 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1103,7 +1103,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From ee0c94612686004b795685062285d561e08409da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1413/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8258094799..37ee0cc5b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From c5d87972e3d127db9faa6bf545dfa21f5853d297 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1414/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 37ee0cc5b2..d8d4bc11ba 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1731,3 +1731,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index ab51e19a7b..d0d7f7e038 100644 --- a/config.c +++ b/config.c @@ -859,7 +859,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 26f7579dcb..008d922044 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -518,4 +518,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index a2c9d1e24a..30d66a94c0 100644 --- a/path.c +++ b/path.c @@ -353,7 +353,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From bf458f5c59afd12abb5393b6aa14e47fc8d302aa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1415/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 2af8f10c83..0e83b410c7 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -870,6 +870,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 21b602ee90c86779eb23a8e5914f3895cb823aa7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1416/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 8ba5b4e5c70fa34815eede561fbc131353b07244 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1417/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 9317b38935..576ac68d57 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 94e27e43131f56177481a6415bdeb88cfc07e7d6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1418/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 0e83b410c7..a0c85b2185 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 86a7918970df03852b0dee02a3da2b4b9d408d41 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1419/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From 3f91f5a8a2f425c57ff4fecee67ea1367d21e4ed Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1420/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 283b412c83..102b11e1d6 100644 --- a/cache.h +++ b/cache.h @@ -721,7 +721,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index d8d4bc11ba..1add521c6a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1749,3 +1749,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 008d922044..420cb84962 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -183,6 +183,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 30d66a94c0..0e560cabac 100644 --- a/path.c +++ b/path.c @@ -768,10 +768,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 81602917a8de41c9c4c9d6991402bac81bc792e9 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1421/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 4a777a63adab01740c2ffab9d819fe20c9d16f8a Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1422/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 1add521c6a..3efdefd441 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1752,23 +1752,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From b150e0a7f242e0e18f782971703ef04f542e3195 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1423/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0d36b56d18..3c9a8aad91 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1143,6 +1143,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From a6f8722d049d9a7291b665a85f0eae4f1772125b Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1424/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 3a42321a9fd40d645a563262c7a1754e3b239b90 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1425/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3efdefd441..283b612599 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -701,11 +701,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From b358fc1d527b7b6c0a0b849b76977efa68e2a7da Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1426/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 15377d69794826addaee8aeff7d27b767ec06822 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1427/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 93685cb61a6003e4706e6ecd6bed13972bb8a4dc Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1428/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From 186ab107133b09ebea02cc9ef0d39acb215826b7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1429/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 6a73efb8c0a2b597633ded8c0cde5cbcb76613f3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1430/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a85e2f6319..7e6cff0448 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3834,6 +3834,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 00da0e1c293b77a8aa1483c71324794ec7cfb106 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1431/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7e6cff0448..ec0f17b463 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3849,7 +3849,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 36d0bc287553e37db1dc8bb0f5ccb4b0aae8a4f1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 26 Aug 2010 14:34:07 +0200 Subject: [PATCH 1432/3720] Fix compile error on MinGW The only difference between the declarations and function definitions here is the use of 'internal_function'. If _LIBC is not defined and __i386__ is, then this actually means something. Signed-off-by: Johannes Schindelin --- compat/regex/regexec.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index 0194965c5d..44f6fac724 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -40,19 +40,24 @@ static reg_errcode_t re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, size_t nmatch, regmatch_t pmatch[], - int eflags); + int eflags) + internal_function; static int re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, - int stop, int ret_len); + int stop, int ret_len) + internal_function; static int re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, struct re_registers *regs, - int ret_len); + int ret_len) + internal_function; static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, - int nregs, int regs_allocated); -static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); + int nregs, int regs_allocated) + internal_function; +static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) + internal_function; static int check_matching (re_match_context_t *mctx, int fl_longest_match, int *p_match_first) internal_function; static int check_halt_state_context (const re_match_context_t *mctx, @@ -353,6 +358,7 @@ weak_alias (__re_search_2, re_search_2) #endif static int +internal_function re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, @@ -397,6 +403,7 @@ re_search_2_stub (struct re_pattern_buffer *bufp, otherwise the position of the match is returned. */ static int +internal_function re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, @@ -484,6 +491,7 @@ re_search_stub (struct re_pattern_buffer *bufp, } static unsigned +internal_function re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs, int regs_allocated) @@ -614,6 +622,7 @@ re_exec (s) (START + RANGE >= 0 && START + RANGE <= LENGTH) */ static reg_errcode_t +internal_function re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, @@ -938,6 +947,7 @@ re_search_internal (const regex_t *preg, } static reg_errcode_t +internal_function prune_impossible_nodes (re_match_context_t *mctx) { const re_dfa_t *const dfa = mctx->dfa; From d624ff33f48252eaaae6b0dfea289e017be4fa53 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1433/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 0a5011f615..6490206411 100644 --- a/http.c +++ b/http.c @@ -2,6 +2,7 @@ #include "pack.h" #include "sideband.h" #include "run-command.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -137,6 +138,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -144,17 +157,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 92d45630cc11203d2a62be7755a9c7ec92ec0c56 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Mon, 27 Sep 2010 07:01:59 -0400 Subject: [PATCH 1434/3720] Fix Windows-specific macro redefinition warning. shell.c defines macro HELP_COMMAND which collides with a like-named macro from winuser.h. Avoid collision by sanitizing preprocessor namespace after including Windows headers. Acked-by: Johannes Schindelin Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 849f37c02b..be6e80fc05 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -78,6 +78,12 @@ struct itimerval { }; #define ITIMER_REAL 0 +/* + * sanitize preprocessor namespace polluted by Windows headers defining + * macros which collide with git local versions + */ +#undef HELP_COMMAND /* from winuser.h */ + /* * trivial stubs */ From 6ddc4d9fb21bc826b929edfb0c8413ea74cb913b Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Mon, 27 Sep 2010 07:02:17 -0400 Subject: [PATCH 1435/3720] Add MinGW-specific execv() override. As of 2dbc887e, shell.c employs execv(), so provide a MinGW-specific mingw_execv() override, complementing existing mingw_execvp() and cousins. As a bonus, this also resolves a compilation warning due to an execv() prototype mismatch between Linux and MinGW. Linux expects the second argument to be (char *const *), whereas MinGW expects (const char *const *). Acked-by: Johannes Schindelin Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- compat/mingw.c | 5 +++++ compat/mingw.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 283b612599..1829e94cd8 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1106,6 +1106,11 @@ void mingw_execvp(const char *cmd, char *const *argv) free_path_split(path); } +void mingw_execv(const char *cmd, char *const *argv) +{ + mingw_execve(cmd, argv, environ); +} + static char **copy_environ(void) { char **env; diff --git a/compat/mingw.h b/compat/mingw.h index be6e80fc05..5587d140a8 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -251,6 +251,8 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env, int fhin, int fhout, int fherr); void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp +void mingw_execv(const char *cmd, char *const *argv); +#define execv mingw_execv static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); } From aae4d4347b5fb19f00b5fc5b9465184a67fdd95a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1436/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index 56a4e0af6b..13118161c7 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die ("Could not open '%s' for writing.", file); From 91d6192197af2448fe677446df4aa8a7dc42eb98 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1437/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 00f1d113cf..d7b857f8d9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 808641c32efa8cddeed041cd3d30934327947f37 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:09:26 -0700 Subject: [PATCH 1438/3720] Revert "Tests: make sure that $DIFF is non-empty" This reverts commit bf458f5c59afd12abb5393b6aa14e47fc8d302aa, because it is apparently no longer necessary. --- t/test-lib.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index a0c85b2185..b50d723984 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -874,8 +874,6 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS -DIFF="${DIFF:-diff}" - if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 793b0fc2c7b957cd4b15ccbe978d0708062da847 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 1439/3720] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3b2477be5f..912c4256fd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 785039ba99527548ea17430fb1ebfbf9a9d41b33 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1440/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 912c4256fd..74c799ad38 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 9d9272d0a754f1d698da0e0cb2992abe44ebfd69 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 1441/3720] MinGW: fix stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Includes squashed fix st_mode for symlink dirs Signed-off-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 39 +++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f2d9e1fd97..ee8f3be5b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -192,8 +192,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -209,6 +212,25 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -220,12 +242,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct stat *buf) +static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -244,7 +266,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 74c799ad38..47839663be 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -235,10 +235,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 59f304b19f33af5978be9043d1981aea497d2e6a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 1442/3720] MinGW: Report errors when failing to launch the html browser. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ee8f3be5b2..431e32265d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1417,6 +1417,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1426,9 +1427,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 459db2880ebf2b355d22e24105d4336d354d2390 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:45:35 +0200 Subject: [PATCH 1443/3720] merge-octopus: Work around environment issue on Windows For some reason, the environment variables get upper-cased when a subprocess is launched on Windows. Cope with that. [PT: fixed typo in the char range noted by junio] Signed-off-by: Johannes Schindelin Signed-off-by: Pat Thoyts --- git-merge-octopus.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 615753c83c..8643f74cb0 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,6 +61,11 @@ do esac eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} + if test "$SHA1" = "$pretty_name" + then + SHA1_UP="$(echo "$SHA1" | tr a-z A-Z)" + eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} + fi common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $pretty_name" From 0535a3c66f46e35f31af450c33c92e9185255ef8 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 27 Sep 2010 22:02:57 +0100 Subject: [PATCH 1444/3720] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Moves the NOT_MINGW prereq from t5503 into the test library. Signed-off-by: Pat Thoyts --- t/t1300-repo-config.sh | 6 +++--- t/t5503-tagfollow.sh | 9 ++------- t/test-lib.sh | 1 + 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 074f2f2e3e..d0ab8ffe1b 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,13 +701,13 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NOT_MINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test "${HOME+set}" +if test_have_prereq NOT_MINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -730,7 +730,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success 'get --path copes with unset $HOME' ' +test_expect_success NOT_MINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 8a298a655f..b6b1fc30cd 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -4,14 +4,9 @@ test_description='test automatic tag following' . ./test-lib.sh -case $(uname -s) in -*MINGW*) +if !test_have_prereq NOT_MINGW; then say "GIT_DEBUG_SEND_PACK not supported - skipping tests" - ;; -*) - test_set_prereq NOT_MINGW - ;; -esac +fi # End state of the repository: # diff --git a/t/test-lib.sh b/t/test-lib.sh index 830e5e7360..a85e7954ad 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -975,6 +975,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NOT_MINGW ;; esac From 66d39c5f73fbe74bd284e3dcd2fab9b7613ea303 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Sun, 12 Sep 2010 10:37:24 +0100 Subject: [PATCH 1445/3720] Do not strip CR when grepping HTTP headers. By default, MSYS grep reads in text-mode and converts CRLF into LF line endings. For testing HTTP use binary mode (-U) as checking is done for CR in HTTP headers Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t5560-http-backend-noserver.sh | 2 ++ t/test-lib.sh | 1 + 2 files changed, 3 insertions(+) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index 94f9d2e8e0..913e5e5df7 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -5,6 +5,8 @@ test_description='test git-http-backend-noserver' HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" +test_have_prereq MINGW && export GREP_OPTIONS=-U + run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ diff --git a/t/test-lib.sh b/t/test-lib.sh index a85e7954ad..2af8f10c83 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -970,6 +970,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 0878369456847115edf478bf45bc13196b3b0dcb Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Fri, 17 Sep 2010 14:27:56 +0100 Subject: [PATCH 1446/3720] Skip 'git archive --remote' test on msysGit This test requires git daemon support which is not available on msysgit Signed-off-by: Pat Thoyts --- t/t5000-tar-tree.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 27bfba55bd..cff1b3e050 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -94,7 +94,7 @@ test_expect_success 'git archive with --output' \ 'git archive --output=b4.tar HEAD && test_cmp b.tar b4.tar' -test_expect_success 'git archive --remote' \ +test_expect_success NOT_MINGW 'git archive --remote' \ 'git archive --remote=. HEAD >b5.tar && test_cmp b.tar b5.tar' From a2253b9068ea0890436131a23310916d17fcb702 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Fri, 17 Sep 2010 09:16:01 -0400 Subject: [PATCH 1447/3720] Side-step sed line-ending "corruption" leading to t6038 failure. By default, MSYS sed throws away CR from CRLF line-endings. Tests t6038.5 and t6038.6 employ sed to normalize conflict output of git-merge for validation purposes. These tests expect CRLF line-endings to be present in the normalized output of git-merge, and thus fail when sed undesirably removes CR. Fix by employing sed's -b/--binary switch to suppress its default behavior of dropping CR characters. Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t6038-merge-text-auto.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh index 52d0dc4bb8..460bf741b5 100755 --- a/t/t6038-merge-text-auto.sh +++ b/t/t6038-merge-text-auto.sh @@ -14,6 +14,8 @@ test_description='CRLF merge conflict across text=auto change . ./test-lib.sh +test_have_prereq MINGW && SED_OPTIONS=-b + test_expect_success setup ' git config core.autocrlf false && @@ -60,7 +62,7 @@ test_expect_success setup ' test_expect_success 'set up fuzz_conflict() helper' ' fuzz_conflict() { - sed -e "s/^\([<>=]......\) .*/\1/" "$@" + sed $SED_OPTIONS -e "s/^\([<>=]......\) .*/\1/" "$@" } ' From e6c3d574035f4453c87f16ff4f6b649718758145 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 20 Jul 2010 19:29:16 -0400 Subject: [PATCH 1448/3720] Side-step MSYS-specific path "corruption" leading to t5560 failure. Upon program invocation, MSYS converts environment variables containing path-like values from Unix-style to DOS-style under the assumption that the program being invoked understands only DOS-style pathnames. For instance, the Unix-style path /msysgit is translated to c:/msysgit. For test t5560, the path being requested from git-http-backend is specified via environment variable PATH_INFO as a URL path of the form /repo.git/foobar, which git-http-backend combines with GIT_PROJECT_ROOT to determine the actual physical path within the repository. This is a case where MSYS's conversion of the path-like value of PATH_INFO causes harm, for two reasons. First, the resulting converted path, when joined with GIT_PROJECT_ROOT is bogus (for instance, "C:/msysgit/git/t/trash-zzz/C:/msysgit/repo.git/HEAD"). Second, the converted PATH_INFO path is rejected by git-http-backend as an 'alias' due to validation failure on the part of daemon_avoid_alias(). Unfortunately, the standard work-around of doubling the leading slash (i.e. //repo.git/foobar) to suppress MSYS path conversion works only for command-line arguments, but not for environment variables. Consequently, side step the problem by instead passing git-http-backend an already-constructed full path rather than components GIT_PROJECT_ROOT and PATH_INFO. Signed-off-by: Eric Sunshine --- t/t5560-http-backend-noserver.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index 913e5e5df7..0ad7ce07c4 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -10,8 +10,7 @@ test_have_prereq MINGW && export GREP_OPTIONS=-U run_backend() { echo "$2" | QUERY_STRING="${1#*\?}" \ - GIT_PROJECT_ROOT="$HTTPD_DOCUMENT_ROOT_PATH" \ - PATH_INFO="${1%%\?*}" \ + PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%\?*}" \ git http-backend >act.out 2>act.err } From 7d42fa83fbbdc43a78d0940c1324e4deb1eef9e7 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 30 Sep 2010 14:24:07 +0100 Subject: [PATCH 1449/3720] git-am: fix detection of absolute paths for windows Add an is_absolute_path function to abstract out platform differences in checking for an absolute or relative path. Specifically fixes t4150-am on Windows. [PT: updated following suggestion from j6t to support \* and //*] Signed-off-by: Johannes Sixt Signed-off-by: Pat Thoyts --- git-am.sh | 12 ++++++------ git-sh-setup.sh | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/git-am.sh b/git-am.sh index de116a29ef..df09b42840 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,12 +444,12 @@ else set x first= } - case "$arg" in - /*) - set "$@" "$arg" ;; - *) - set "$@" "$prefix$arg" ;; - esac + if is_absolute_path "$arg" + then + set "$@" "$arg" + else + set "$@" "$prefix$arg" + fi done shift fi diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 6131670860..58d30c9388 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -209,5 +209,20 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + is_absolute_path () { + case "$1" in + [/\\]* | [A-Za-z]:*) + return 0 ;; + esac + return 1 + } ;; +*) + is_absolute_path () { + case "$1" in + /*) + return 0 ;; + esac + return 1 + } esac From 1958254b61202d3b7fd0749e62545865717c7301 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 23 Sep 2010 17:35:25 +0000 Subject: [PATCH 1450/3720] mingw: do not crash on open(NULL, ...) fetch_and_setup_pack_index() apparently pass a NULL-pointer to parse_pack_index(), which in turn pass it to check_packed_git_idx(), which again pass it to open(). Since open() already sets errno correctly for the NULL-case, let's just avoid the problematic strcmp. [PT: squashed in fix for freopen which was missed first time round] Acked-by: Johannes Sixt Signed-off-by: Erik Faye-Lund Signed-off-by: Pat Thoyts --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 431e32265d..bd1403a1d5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -127,7 +127,7 @@ int mingw_open (const char *filename, int oflags, ...) mode = va_arg(args, int); va_end(args); - if (!strcmp(filename, "/dev/null")) + if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; fd = open(filename, oflags, mode); @@ -160,7 +160,7 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { - if (!strcmp(filename, "/dev/null")) + if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; return fopen(filename, otype); } From 3154ec02be464ee264119c124572f55a65992b7e Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1451/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7f6b2109bd..6fcc32c353 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 9d4886c716..84bbf3ed49 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -327,6 +327,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 33decd942d..3125834ebf 100644 --- a/cache.h +++ b/cache.h @@ -559,6 +559,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index bd1403a1d5..710150f442 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 47839663be..56e58ba341 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -281,6 +278,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 4b0a82040e..ab51e19a7b 100644 --- a/config.c +++ b/config.c @@ -643,6 +643,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index de5581fe51..eaf908b6fb 100644 --- a/environment.c +++ b/environment.c @@ -55,6 +55,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 2af8d3edbe..ea5ab439c1 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -526,4 +526,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From f29a4ab6cd3aab194b84d23d0c234411832a5f35 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1452/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 710150f442..98163da387 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From d9305838a4e4c3d69552bc4d3f20153239630b2f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1453/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From afe8d1d0d1b728d75f4b7890a0194427b821335b Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1454/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 4617f29c26..cb594fe019 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1226,9 +1226,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2028,7 +2025,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2040,12 +2037,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2066,18 +2070,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2098,20 +2099,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From f86ceeafb62433b157e18db7488ec72bba75b573 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1455/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 98163da387..49c594f29c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 56e58ba341..220ae907cd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 42b51e95d20ea110675bee4b812ebee39d2b73e8 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1456/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 49c594f29c..4b40c6f4e4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1279,7 +1295,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From c8dd890132a70f766251d85c3e4b984674687120 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1457/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4b40c6f4e4..601656cff0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1336,6 +1389,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 9ac1253f62d217ebc1fef842324e448ae1cd1406 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1458/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 601656cff0..2443bc4746 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 220ae907cd..cf69d39a06 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From ec9d1c4f6a3925cc8b4d55c0baf302b4bd5e7104 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1459/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cb594fe019..0d36b56d18 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1143,6 +1143,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From aad031320130b38a62ecaa0860fb9551a04a1225 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1460/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..1fa5acb910 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9417,7 +9417,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 8414d01d3eca46a147634cc6fd43cc719ef5198a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1461/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7fe8883ae0..28f67ce1d4 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -318,4 +318,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 2d22608579c0f16fa2b8e9401af57dd24e7f80fd Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1462/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2443bc4746..01ae468579 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 732c56609a675e9d027cc6c45ccf75ac38d811e8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1463/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 294584452b..3a18a3fd72 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -213,6 +213,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index c9300f3c8b..5cbde26ba6 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -697,6 +697,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -713,6 +717,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -739,8 +747,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -755,6 +771,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -790,6 +810,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From bbfeebce11aca705c98b6315f91c058fd962db8c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1464/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 6fcc32c353..16b4f741f0 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1607,6 +1607,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b11da79c9c..e721c74b87 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From bc1e462b7e9f8fcc030ebe72cfb108680546169e Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1465/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 01ae468579..8258094799 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 8907b5bf17913fa4a925f1cf13791f48e322c55a Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1466/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index e1f29a72a1..15e63df59e 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1017,7 +1017,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 2a146966334215b74a2a699bcd8e69fa54912662 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1467/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 15e63df59e..eee1a8fe3d 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1103,7 +1103,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 3142f2493ef4ea02409cd3d11165af0162f9fd98 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1468/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8258094799..37ee0cc5b2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 396f077af9d0703f1a5e3be2e9b3b0e8adb8f902 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1469/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 37ee0cc5b2..d8d4bc11ba 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1731,3 +1731,21 @@ struct dirent *mingw_readdir(DIR *dir) return (struct dirent*)&dir->dd_dir; } #endif // !NO_MINGW_REPLACE_READDIR + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index cf69d39a06..8104039ee1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -337,3 +337,6 @@ struct dirent *mingw_readdir(DIR *dir); * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index ab51e19a7b..d0d7f7e038 100644 --- a/config.c +++ b/config.c @@ -859,7 +859,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index ea5ab439c1..599d5b054e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -530,4 +530,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index a2c9d1e24a..30d66a94c0 100644 --- a/path.c +++ b/path.c @@ -353,7 +353,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 843dc1b7af05e89db18d2f2321b4637abd6cd50b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 11 Jun 2010 18:49:06 +0200 Subject: [PATCH 1470/3720] Tests: make sure that $DIFF is non-empty Signed-off-by: Johannes Schindelin --- t/test-lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 2af8f10c83..0e83b410c7 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -870,6 +870,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +DIFF="${DIFF:-diff}" + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 4fb1d1de6dc3f3995f6aede26bcb3bfea1c653b2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1471/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 2746169514..8962a737e3 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 163ad8c32574b7eed0655d9b1863049e446776a6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1472/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index df09b42840..e7f649a266 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From b3f15d8bc3dddeabc8312a0c0758718300390310 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1473/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 0e83b410c7..a0c85b2185 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 465024aac096d6c4358be7b2a21da34cbb2b99a2 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Jul 2010 21:48:47 -0400 Subject: [PATCH 1474/3720] Fix 'clone' failure at DOS root directory. Cloning via relative path fails for a project residing immediately under the root directory of a DOS drive. For instance, for project c:/foo, issuing "cd c:/" followed by "git clone foo bar" fails with error "Unable to find remote helper for 'c'". The problem is caused by make_nonrelative_path() incorrectly returning c://foo rather than c:/foo for input "foo". The bogus path c://foo is misinterpreted by transport_get() as a URL with unrecognized protocol "c", hence the missing remote helper error. Fix make_nonrelative_path() to return c:/foo rather than c://foo (and /foo rather than //foo on Unix). Resolves msysgit issue #501: http://code.google.com/p/msysgit/issues/detail?id=501 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- abspath.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index c91a29cb29..6b4dfe2e1a 100644 --- a/abspath.c +++ b/abspath.c @@ -108,10 +108,15 @@ const char *make_nonrelative_path(const char *path) if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { + size_t len; + const char *fmt; const char *cwd = get_pwd_cwd(); if (!cwd) die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + len = strlen(cwd); + /* For cwd c:/, return c:/foo rather than URL-like c://foo */ + fmt = len > 0 && is_dir_sep(cwd[len-1]) ? "%s%s" : "%s/%s"; + if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } return buf; From 4eec1055c615ad0904b340430875d5f41a5f00c2 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1475/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 3125834ebf..561bb04a5b 100644 --- a/cache.h +++ b/cache.h @@ -728,7 +728,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index d8d4bc11ba..1add521c6a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1749,3 +1749,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 8104039ee1..dbb179c450 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -270,6 +270,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 599d5b054e..f9d042bb9f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -195,6 +195,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 30d66a94c0..0e560cabac 100644 --- a/path.c +++ b/path.c @@ -768,10 +768,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 300066acf7ff5a766130d03b7078f2d2bce651a4 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1476/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From a2a5ac3e500571091e6f351335be26574945af3c Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1477/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 1add521c6a..3efdefd441 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1752,23 +1752,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 09a6798d737cb43633f1bbabacf15e80acaf2b2f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1478/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0d36b56d18..3c9a8aad91 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1143,6 +1143,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From bd2fa95c186a433023f24f64082fb5902e780cf8 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1479/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1fa5acb910..b9c895511c 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -355,7 +355,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9417,18 +9417,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9439,6 +9428,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From f54827c386c3a13378caf43527191963359a2007 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1480/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3efdefd441..283b612599 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -701,11 +701,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From f6ee2a3b4a31f9feafdd9e68100e2eef423e6514 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1481/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index dbb179c450..849f37c02b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -260,9 +260,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 9e9c8d7b8adbb69b46c7bf2d43bd6b4a3c51e9cd Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1482/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 03c5b4e6c0fbdb5968afabf89d24a8986ebae1ed Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1483/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From 459ce0ecb5fbe9740aebdf0ed7212ca7015cd5bb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1484/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From a826102d004e78928fd64133b3a02883ee475f9c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1485/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a85e2f6319..7e6cff0448 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3834,6 +3834,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 0b290b23b268f30552038ecfb15f5d92b552fc26 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1486/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7e6cff0448..ec0f17b463 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3849,7 +3849,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From eacf19ab04b082861eccf14ca86107d5f29ed870 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1487/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 0a5011f615..6490206411 100644 --- a/http.c +++ b/http.c @@ -2,6 +2,7 @@ #include "pack.h" #include "sideband.h" #include "run-command.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -137,6 +138,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -144,17 +157,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 3cc91e351ec0d88e02df079e9759ba2757d4e7e7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1488/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index 56a4e0af6b..13118161c7 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die ("Could not open '%s' for writing.", file); From ab2741c4d56fcfed86d5712d094f0071abb5cb57 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1489/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 00f1d113cf..d7b857f8d9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 4b895e9ae78a570706898a9030f9fcc11294f74b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:09:26 -0700 Subject: [PATCH 1490/3720] Revert "Tests: make sure that $DIFF is non-empty" This reverts commit bf458f5c59afd12abb5393b6aa14e47fc8d302aa, because it is apparently no longer necessary. --- t/test-lib.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index a0c85b2185..b50d723984 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -874,8 +874,6 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOB . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS -DIFF="${DIFF:-diff}" - if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" From 87dd0451156c5d7883a495d10d560ac70f192867 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1491/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 3d5f6ace97..7e5b60a516 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -17,6 +17,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "attr.h" #ifndef NO_PTHREADS #include @@ -183,6 +184,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -193,6 +210,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -597,6 +617,9 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) continue; if (!pathspec_matches(paths, ce->name, opt->max_depth)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -1007,6 +1030,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die("no pattern given."); From 99bf23b2eda527c98703eaa993ef4e54b5cd94f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:36 +0700 Subject: [PATCH 1492/3720] Add struct pathspec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old pathspec structure remains as pathspec.raw[]. New things are stored in pathspec.items[]. There's no guarantee that the pathspec order in raw[] is exactly as in items[]. raw[] is external (source) data and is untouched by pathspec manipulation functions. It eases migration from old const char ** to this new struct. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- cache.h | 11 +++++++++++ dir.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/cache.h b/cache.h index 2ef2fa3a5e..9eeecc2e88 100644 --- a/cache.h +++ b/cache.h @@ -493,6 +493,17 @@ extern int index_name_is_other(const struct index_state *, const char *, int); extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int); extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int); +struct pathspec { + const char **raw; /* get_pathspec() result, not freed by free_pathspec() */ + int nr; + struct pathspec_item { + const char *match; + int len; + } *items; +}; + +extern int init_pathspec(struct pathspec *, const char **); +extern void free_pathspec(struct pathspec *); extern int ce_path_match(const struct cache_entry *ce, const char **pathspec); extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); diff --git a/dir.c b/dir.c index 133f472a1e..a88f2ef1a4 100644 --- a/dir.c +++ b/dir.c @@ -1071,3 +1071,34 @@ int remove_path(const char *name) return 0; } +int init_pathspec(struct pathspec *pathspec, const char **paths) +{ + const char **p = paths; + int i; + + memset(pathspec, 0, sizeof(*pathspec)); + if (!p) + return 0; + while (*p) + p++; + pathspec->raw = paths; + pathspec->nr = p - paths; + if (!pathspec->nr) + return 0; + + pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr); + for (i = 0; i < pathspec->nr; i++) { + struct pathspec_item *item = pathspec->items+i; + const char *path = paths[i]; + + item->match = path; + item->len = strlen(path); + } + return 0; +} + +void free_pathspec(struct pathspec *pathspec) +{ + free(pathspec->items); + pathspec->items = NULL; +} From 9373373d1801c78da666648ce91e358e5e8f2af8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:37 +0700 Subject: [PATCH 1493/3720] diff-no-index: use diff_tree_setup_paths() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit diff_options.{paths,nr_paths} will be removed later. Do not modify them directly. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- diff-no-index.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/diff-no-index.c b/diff-no-index.c index ce9e783407..e48ab92ba1 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -231,8 +231,9 @@ void diff_no_index(struct rev_info *revs, if (prefix) { int len = strlen(prefix); + const char *paths[3]; + memset(paths, 0, sizeof(paths)); - revs->diffopt.paths = xcalloc(2, sizeof(char *)); for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; /* @@ -242,12 +243,12 @@ void diff_no_index(struct rev_info *revs, p = (strcmp(p, "-") ? xstrdup(prefix_filename(prefix, len, p)) : p); - revs->diffopt.paths[i] = p; + paths[i] = p; } + diff_tree_setup_paths(paths, &revs->diffopt); } else - revs->diffopt.paths = argv + argc - 2; - revs->diffopt.nr_paths = 2; + diff_tree_setup_paths(argv + argc - 2, &revs->diffopt); revs->diffopt.skip_stat_unmatch = 1; if (!revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; From e13219fa1a3769cff74ce36acef7a8306795ed52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:38 +0700 Subject: [PATCH 1494/3720] Convert struct diff_options to use struct pathspec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/diff-files.c | 2 +- builtin/diff.c | 4 ++-- builtin/log.c | 2 +- diff-lib.c | 2 +- diff-no-index.c | 4 ++-- diff.h | 4 +--- revision.c | 6 +----- tree-diff.c | 48 ++++++++++++-------------------------------- 8 files changed, 22 insertions(+), 50 deletions(-) diff --git a/builtin/diff-files.c b/builtin/diff-files.c index 951c7c8994..46085f862f 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) (rev.diffopt.output_format & DIFF_FORMAT_PATCH)) rev.combine_merges = rev.dense_combined_merges = 1; - if (read_cache_preload(rev.diffopt.paths) < 0) { + if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } diff --git a/builtin/diff.c b/builtin/diff.c index a43d326363..76c42d834f 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -135,7 +135,7 @@ static int builtin_diff_index(struct rev_info *revs, revs->max_count != -1 || revs->min_age != -1 || revs->max_age != -1) usage(builtin_diff_usage); - if (read_cache_preload(revs->diffopt.paths) < 0) { + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } @@ -237,7 +237,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv revs->combine_merges = revs->dense_combined_merges = 1; setup_work_tree(); - if (read_cache_preload(revs->diffopt.paths) < 0) { + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } diff --git a/builtin/log.c b/builtin/log.c index eaa1ee0fa7..92779a522c 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -89,7 +89,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, rev->always_show_header = 0; if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) { rev->always_show_header = 0; - if (rev->diffopt.nr_paths != 1) + if (rev->diffopt.pathspec.nr != 1) usage("git logs can only follow renames on one pathname at a time"); } for (i = 1; i < argc; i++) { diff --git a/diff-lib.c b/diff-lib.c index 392ce2bef0..3b809f2e0d 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -501,7 +501,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) active_nr = dst - active_cache; init_revisions(&revs, NULL); - revs.prune_data = opt->paths; + revs.prune_data = opt->pathspec.raw; tree = parse_tree_indirect(tree_sha1); if (!tree) die("bad tree object %s", sha1_to_hex(tree_sha1)); diff --git a/diff-no-index.c b/diff-no-index.c index e48ab92ba1..3a36144687 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -260,8 +260,8 @@ void diff_no_index(struct rev_info *revs, if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); - if (queue_diff(&revs->diffopt, revs->diffopt.paths[0], - revs->diffopt.paths[1])) + if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0], + revs->diffopt.pathspec.raw[1])) exit(1); diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); diffcore_std(&revs->diffopt); diff --git a/diff.h b/diff.h index bf2f44d840..6497b71aa8 100644 --- a/diff.h +++ b/diff.h @@ -133,9 +133,7 @@ struct diff_options { FILE *file; int close_file; - int nr_paths; - const char **paths; - int *pathlens; + struct pathspec pathspec; change_fn_t change; add_remove_fn_t add_remove; diff_format_fn_t format_callback; diff --git a/revision.c b/revision.c index b1c18906ba..b2a5867dcd 100644 --- a/revision.c +++ b/revision.c @@ -553,11 +553,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) left_first = left_count < right_count; init_patch_ids(&ids); - if (revs->diffopt.nr_paths) { - ids.diffopts.nr_paths = revs->diffopt.nr_paths; - ids.diffopts.paths = revs->diffopt.paths; - ids.diffopts.pathlens = revs->diffopt.pathlens; - } + ids.diffopts.pathspec = revs->diffopt.pathspec; /* Compute patch-ids for one side */ for (p = list; p; p = p->next) { diff --git a/tree-diff.c b/tree-diff.c index cd659c6fe4..7a4cc4b71d 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -100,16 +100,17 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int int pathlen; int never_interesting = -1; - if (!opt->nr_paths) + if (!opt->pathspec.nr) return 1; sha1 = tree_entry_extract(desc, &path, &mode); pathlen = tree_entry_len(path, sha1); - for (i = 0; i < opt->nr_paths; i++) { - const char *match = opt->paths[i]; - int matchlen = opt->pathlens[i]; + for (i = 0; i < opt->pathspec.nr; i++) { + const struct pathspec_item *item = opt->pathspec.items+i; + const char *match = item->match; + int matchlen = item->len; int m = -1; /* signals that we haven't called strncmp() */ if (baselen >= matchlen) { @@ -289,7 +290,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru if (DIFF_OPT_TST(opt, QUICK) && DIFF_OPT_TST(opt, HAS_CHANGES)) break; - if (opt->nr_paths) { + if (opt->pathspec.nr) { skip_uninteresting(t1, base, baselen, opt); skip_uninteresting(t2, base, baselen, opt); } @@ -348,7 +349,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co DIFF_OPT_SET(&diff_opts, RECURSIVE); DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - diff_opts.single_follow = opt->paths[0]; + diff_opts.single_follow = opt->pathspec.raw[0]; diff_opts.break_opt = opt->break_opt; paths[0] = NULL; diff_tree_setup_paths(paths, &diff_opts); @@ -368,15 +369,16 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co * diff_queued_diff, we will also use that as the path in * the future! */ - if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) { + if ((p->status == 'R' || p->status == 'C') && + !strcmp(p->two->path, opt->pathspec.raw[0])) { /* Switch the file-pairs around */ q->queue[i] = choice; choice = p; /* Update the path we use from now on.. */ diff_tree_release_paths(opt); - opt->paths[0] = xstrdup(p->one->path); - diff_tree_setup_paths(opt->paths, opt); + opt->pathspec.raw[0] = xstrdup(p->one->path); + diff_tree_setup_paths(opt->pathspec.raw, opt); /* * The caller expects us to return a set of vanilla @@ -451,36 +453,12 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_ return retval; } -static int count_paths(const char **paths) -{ - int i = 0; - while (*paths++) - i++; - return i; -} - void diff_tree_release_paths(struct diff_options *opt) { - free(opt->pathlens); + free_pathspec(&opt->pathspec); } void diff_tree_setup_paths(const char **p, struct diff_options *opt) { - opt->nr_paths = 0; - opt->pathlens = NULL; - opt->paths = NULL; - - if (p) { - int i; - - opt->paths = p; - opt->nr_paths = count_paths(p); - if (opt->nr_paths == 0) { - opt->pathlens = NULL; - return; - } - opt->pathlens = xmalloc(opt->nr_paths * sizeof(int)); - for (i=0; i < opt->nr_paths; i++) - opt->pathlens[i] = strlen(p[i]); - } + init_pathspec(&opt->pathspec, p); } From a79ca12d0a0cf4f731d26a6a0bcd1ad4eaf5f0ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:39 +0700 Subject: [PATCH 1495/3720] tree_entry_interesting(): remove dependency on struct diff_options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function can be potentially used in more places than just tree-diff.c. "struct diff_options" does not make much sense outside diff_tree_sha1(). While removing the use of diff_options, it also removes tree_entry_extract() call, which means S_ISDIR() uses the entry->mode directly, without being filtered by canon_mode() (called internally inside tree_entry_extract). The only use of the mode information in this function is to check the type of the entry by giving it to S_ISDIR() macro, and the result does not change with or without canon_mode(), so it is ok to bypass tree_entry_extract(). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- tree-diff.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/tree-diff.c b/tree-diff.c index 7a4cc4b71d..57e89091c8 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -91,24 +91,19 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const * - zero for no * - negative for "no, and no subsequent entries will be either" */ -static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt) +static int tree_entry_interesting(const struct name_entry *entry, const char *base, int baselen, const struct pathspec *ps) { - const char *path; - const unsigned char *sha1; - unsigned mode; int i; int pathlen; int never_interesting = -1; - if (!opt->pathspec.nr) + if (!ps || !ps->nr) return 1; - sha1 = tree_entry_extract(desc, &path, &mode); + pathlen = tree_entry_len(entry->path, entry->sha1); - pathlen = tree_entry_len(path, sha1); - - for (i = 0; i < opt->pathspec.nr; i++) { - const struct pathspec_item *item = opt->pathspec.items+i; + for (i = 0; i < ps->nr; i++) { + const struct pathspec_item *item = ps->items+i; const char *match = item->match; int matchlen = item->len; int m = -1; /* signals that we haven't called strncmp() */ @@ -148,7 +143,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int * Does match sort strictly earlier than path * with their common parts? */ - m = strncmp(match, path, + m = strncmp(match, entry->path, (matchlen < pathlen) ? matchlen : pathlen); if (m < 0) continue; @@ -175,7 +170,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int if (matchlen > pathlen) { if (match[pathlen] != '/') continue; - if (!S_ISDIR(mode)) + if (!S_ISDIR(entry->mode)) continue; } @@ -184,7 +179,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int * we cheated and did not do strncmp(), so we do * that here. */ - m = strncmp(match, path, pathlen); + m = strncmp(match, entry->path, pathlen); /* * If common part matched earlier then it is a hit, @@ -207,8 +202,7 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_ if (all_interesting) show = 1; else { - show = tree_entry_interesting(desc, base, baselen, - opt); + show = tree_entry_interesting(&desc->entry, base, baselen, &opt->pathspec); if (show == 2) all_interesting = 1; } @@ -267,7 +261,7 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele if (all_interesting) show = 1; else { - show = tree_entry_interesting(t, base, baselen, opt); + show = tree_entry_interesting(&t->entry, base, baselen, &opt->pathspec); if (show == 2) all_interesting = 1; } From 387229782d4013160c61a230a502c59d62504db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:40 +0700 Subject: [PATCH 1496/3720] Move tree_entry_interesting() to tree-walk.c and export it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- tree-diff.c | 110 --------------------------------------------------- tree-walk.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tree-walk.h | 2 + 3 files changed, 114 insertions(+), 110 deletions(-) diff --git a/tree-diff.c b/tree-diff.c index 57e89091c8..28a69dc67f 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -82,116 +82,6 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const return 0; } -/* - * Is a tree entry interesting given the pathspec we have? - * - * Return: - * - 2 for "yes, and all subsequent entries will be" - * - 1 for yes - * - zero for no - * - negative for "no, and no subsequent entries will be either" - */ -static int tree_entry_interesting(const struct name_entry *entry, const char *base, int baselen, const struct pathspec *ps) -{ - int i; - int pathlen; - int never_interesting = -1; - - if (!ps || !ps->nr) - return 1; - - pathlen = tree_entry_len(entry->path, entry->sha1); - - for (i = 0; i < ps->nr; i++) { - const struct pathspec_item *item = ps->items+i; - const char *match = item->match; - int matchlen = item->len; - int m = -1; /* signals that we haven't called strncmp() */ - - if (baselen >= matchlen) { - /* If it doesn't match, move along... */ - if (strncmp(base, match, matchlen)) - continue; - - /* - * If the base is a subdirectory of a path which - * was specified, all of them are interesting. - */ - if (!matchlen || - base[matchlen] == '/' || - match[matchlen - 1] == '/') - return 2; - - /* Just a random prefix match */ - continue; - } - - /* Does the base match? */ - if (strncmp(base, match, baselen)) - continue; - - match += baselen; - matchlen -= baselen; - - if (never_interesting) { - /* - * We have not seen any match that sorts later - * than the current path. - */ - - /* - * Does match sort strictly earlier than path - * with their common parts? - */ - m = strncmp(match, entry->path, - (matchlen < pathlen) ? matchlen : pathlen); - if (m < 0) - continue; - - /* - * If we come here even once, that means there is at - * least one pathspec that would sort equal to or - * later than the path we are currently looking at. - * In other words, if we have never reached this point - * after iterating all pathspecs, it means all - * pathspecs are either outside of base, or inside the - * base but sorts strictly earlier than the current - * one. In either case, they will never match the - * subsequent entries. In such a case, we initialized - * the variable to -1 and that is what will be - * returned, allowing the caller to terminate early. - */ - never_interesting = 0; - } - - if (pathlen > matchlen) - continue; - - if (matchlen > pathlen) { - if (match[pathlen] != '/') - continue; - if (!S_ISDIR(entry->mode)) - continue; - } - - if (m == -1) - /* - * we cheated and did not do strncmp(), so we do - * that here. - */ - m = strncmp(match, entry->path, pathlen); - - /* - * If common part matched earlier then it is a hit, - * because we rejected the case where path is not a - * leading directory and is shorter than match. - */ - if (!m) - return 1; - } - return never_interesting; /* No matches */ -} - /* A whole sub-tree went away or appeared */ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen) { diff --git a/tree-walk.c b/tree-walk.c index a9bbf4e235..a2e2a994a5 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -455,3 +455,115 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch free(tree); return retval; } + +/* + * Is a tree entry interesting given the pathspec we have? + * + * Return: + * - 2 for "yes, and all subsequent entries will be" + * - 1 for yes + * - zero for no + * - negative for "no, and no subsequent entries will be either" + */ +int tree_entry_interesting(const struct name_entry *entry, + const char *base, int baselen, + const struct pathspec *ps) +{ + int i; + int pathlen; + int never_interesting = -1; + + if (!ps || !ps->nr) + return 1; + + pathlen = tree_entry_len(entry->path, entry->sha1); + + for (i = 0; i < ps->nr; i++) { + const struct pathspec_item *item = ps->items+i; + const char *match = item->match; + int matchlen = item->len; + int m = -1; /* signals that we haven't called strncmp() */ + + if (baselen >= matchlen) { + /* If it doesn't match, move along... */ + if (strncmp(base, match, matchlen)) + continue; + + /* + * If the base is a subdirectory of a path which + * was specified, all of them are interesting. + */ + if (!matchlen || + base[matchlen] == '/' || + match[matchlen - 1] == '/') + return 2; + + /* Just a random prefix match */ + continue; + } + + /* Does the base match? */ + if (strncmp(base, match, baselen)) + continue; + + match += baselen; + matchlen -= baselen; + + if (never_interesting) { + /* + * We have not seen any match that sorts later + * than the current path. + */ + + /* + * Does match sort strictly earlier than path + * with their common parts? + */ + m = strncmp(match, entry->path, + (matchlen < pathlen) ? matchlen : pathlen); + if (m < 0) + continue; + + /* + * If we come here even once, that means there is at + * least one pathspec that would sort equal to or + * later than the path we are currently looking at. + * In other words, if we have never reached this point + * after iterating all pathspecs, it means all + * pathspecs are either outside of base, or inside the + * base but sorts strictly earlier than the current + * one. In either case, they will never match the + * subsequent entries. In such a case, we initialized + * the variable to -1 and that is what will be + * returned, allowing the caller to terminate early. + */ + never_interesting = 0; + } + + if (pathlen > matchlen) + continue; + + if (matchlen > pathlen) { + if (match[pathlen] != '/') + continue; + if (!S_ISDIR(entry->mode)) + continue; + } + + if (m == -1) + /* + * we cheated and did not do strncmp(), so we do + * that here. + */ + m = strncmp(match, entry->path, pathlen); + + /* + * If common part matched earlier then it is a hit, + * because we rejected the case where path is not a + * leading directory and is shorter than match. + */ + if (!m) + return 1; + } + return never_interesting; /* No matches */ +} diff --git a/tree-walk.h b/tree-walk.h index 7e3e0b5ad1..c12f0a2978 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,4 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } +extern int tree_entry_interesting(const struct name_entry *, const char *, int, const struct pathspec *ps); + #endif From 186d6043c05ddc796a97fa9c139c91c91de31074 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Wed, 15 Dec 2010 22:02:41 +0700 Subject: [PATCH 1497/3720] glossary: define pathspec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- Documentation/glossary-content.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 1f029f8aa0..4ed2a28608 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -273,6 +273,29 @@ This commit is referred to as a "merge commit", or sometimes just a <>, to assist in efficiently accessing the contents of a pack. +[[def_pathspec]]pathspec:: + Pattern used to specify paths. ++ +Pathspecs are used on the command line of "git ls-files", "git +ls-tree", "git grep", "git checkout", and many other commands to +limit the scope of operations to some subset of the tree or +worktree. See the documentation of each command for whether +paths are relative to the current directory or toplevel. The +pathspec syntax is as follows: + +* any path matches itself +* the pathspec up to the last slash represents a + directory prefix. The scope of that pathspec is + limited to that subtree. +* the rest of the pathspec is a pattern for the remainder + of the pathname. Paths relative to the directory + prefix will be matched against that pattern using fnmatch(3); + in particular, '*' and '?' _can_ match directory separators. ++ +For example, Documentation/*.jpg will match all .jpg files +in the Documentation subtree, +including Documentation/chapter_1/figure_1.jpg. + [[def_parent]]parent:: A <> contains a (possibly empty) list of the logical predecessor(s) in the line of development, i.e. its From 8bbcebfd938fbd1c95dc4dd23bc9d754313f43d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:42 +0700 Subject: [PATCH 1498/3720] diff-tree: convert base+baselen to writable strbuf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In traversing trees, a full path is splitted into two parts: base directory and entry. They are however quite often concatenated whenever a full path is needed. Current code allocates a new buffer, do two memcpy(), use it, then release. Instead this patch turns "base" to a writable, extendable buffer. When a concatenation is needed, the callee only needs to append "entry" to base, use it, then truncate the entry out again. "base" must remain unchanged before and after entering a function. This avoids quite a bit of malloc() and memcpy(). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- tree-diff.c | 119 +++++++++++++++++++++++----------------------------- tree-walk.c | 5 ++- tree-walk.h | 2 +- 3 files changed, 57 insertions(+), 69 deletions(-) diff --git a/tree-diff.c b/tree-diff.c index 28a69dc67f..f8772c9142 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -6,34 +6,18 @@ #include "diffcore.h" #include "tree.h" -static char *malloc_base(const char *base, int baselen, const char *path, int pathlen) -{ - char *newbase = xmalloc(baselen + pathlen + 2); - memcpy(newbase, base, baselen); - memcpy(newbase + baselen, path, pathlen); - memcpy(newbase + baselen + pathlen, "/", 2); - return newbase; -} +static void show_entry(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base); -static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen) -{ - char *fullname = xmalloc(baselen + pathlen + 1); - memcpy(fullname, base, baselen); - memcpy(fullname + baselen, path, pathlen); - fullname[baselen + pathlen] = 0; - return fullname; -} - -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base, int baselen); - -static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt) +static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, + struct strbuf *base, struct diff_options *opt) { unsigned mode1, mode2; const char *path1, *path2; const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; - char *fullname; + int old_baselen = base->len; + int retval = 0; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); @@ -42,11 +26,11 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const pathlen2 = tree_entry_len(path2, sha2); cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2); if (cmp < 0) { - show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "-", t1, base); return -1; } if (cmp > 0) { - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "+", t2, base); return 1; } if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2) @@ -57,33 +41,29 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { - show_entry(opt, "-", t1, base, baselen); - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "-", t1, base); + show_entry(opt, "+", t2, base); return 0; } + strbuf_add(base, path1, pathlen1); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) { - int retval; - char *newbase = malloc_base(base, baselen, path1, pathlen1); if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { - newbase[baselen + pathlen1] = 0; opt->change(opt, mode1, mode2, - sha1, sha2, newbase, 0, 0); - newbase[baselen + pathlen1] = '/'; + sha1, sha2, base->buf, 0, 0); } - retval = diff_tree_sha1(sha1, sha2, newbase, opt); - free(newbase); - return retval; + strbuf_addch(base, '/'); + retval = diff_tree_sha1(sha1, sha2, base->buf, opt); + } else { + opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } - - fullname = malloc_fullname(base, baselen, path1, pathlen1); - opt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0); - free(fullname); + strbuf_setlen(base, old_baselen); return 0; } /* A whole sub-tree went away or appeared */ -static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen) +static void show_tree(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base) { int all_interesting = 0; while (desc->size) { @@ -92,30 +72,32 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_ if (all_interesting) show = 1; else { - show = tree_entry_interesting(&desc->entry, base, baselen, &opt->pathspec); + show = tree_entry_interesting(&desc->entry, base, + &opt->pathspec); if (show == 2) all_interesting = 1; } if (show < 0) break; if (show) - show_entry(opt, prefix, desc, base, baselen); + show_entry(opt, prefix, desc, base); update_tree_entry(desc); } } /* A file entry went away or appeared */ -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base, int baselen) +static void show_entry(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base) { unsigned mode; const char *path; const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode); int pathlen = tree_entry_len(path, sha1); + int old_baselen = base->len; + strbuf_add(base, path, pathlen); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) { enum object_type type; - char *newbase = malloc_base(base, baselen, path, pathlen); struct tree_desc inner; void *tree; unsigned long size; @@ -124,25 +106,22 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree if (!tree || type != OBJ_TREE) die("corrupt tree sha %s", sha1_to_hex(sha1)); - if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { - newbase[baselen + pathlen] = 0; - opt->add_remove(opt, *prefix, mode, sha1, newbase, 0); - newbase[baselen + pathlen] = '/'; - } + if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) + opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0); + + strbuf_addch(base, '/'); init_tree_desc(&inner, tree, size); - show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen); - + show_tree(opt, prefix, &inner, base); free(tree); - free(newbase); - } else { - char *fullname = malloc_fullname(base, baselen, path, pathlen); - opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0); - free(fullname); - } + } else + opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0); + + strbuf_setlen(base, old_baselen); } -static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt) +static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, + struct diff_options *opt) { int all_interesting = 0; while (t->size) { @@ -151,7 +130,8 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele if (all_interesting) show = 1; else { - show = tree_entry_interesting(&t->entry, base, baselen, &opt->pathspec); + show = tree_entry_interesting(&t->entry, base, + &opt->pathspec); if (show == 2) all_interesting = 1; } @@ -166,31 +146,36 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele } } -int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) +int diff_tree(struct tree_desc *t1, struct tree_desc *t2, + const char *base_str, struct diff_options *opt) { - int baselen = strlen(base); + struct strbuf base; + int baselen = strlen(base_str); + + strbuf_init(&base, PATH_MAX); + strbuf_add(&base, base_str, baselen); for (;;) { if (DIFF_OPT_TST(opt, QUICK) && DIFF_OPT_TST(opt, HAS_CHANGES)) break; if (opt->pathspec.nr) { - skip_uninteresting(t1, base, baselen, opt); - skip_uninteresting(t2, base, baselen, opt); + skip_uninteresting(t1, &base, opt); + skip_uninteresting(t2, &base, opt); } if (!t1->size) { if (!t2->size) break; - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "+", t2, &base); update_tree_entry(t2); continue; } if (!t2->size) { - show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "-", t1, &base); update_tree_entry(t1); continue; } - switch (compare_tree_entry(t1, t2, base, baselen, opt)) { + switch (compare_tree_entry(t1, t2, &base, opt)) { case -1: update_tree_entry(t1); continue; @@ -203,6 +188,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru } die("git diff-tree: internal error"); } + + strbuf_release(&base); return 0; } diff --git a/tree-walk.c b/tree-walk.c index a2e2a994a5..0830676492 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -466,12 +466,13 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch * - negative for "no, and no subsequent entries will be either" */ int tree_entry_interesting(const struct name_entry *entry, - const char *base, int baselen, + const struct strbuf *base_buf, const struct pathspec *ps) { int i; - int pathlen; + int pathlen, baselen = base_buf->len; int never_interesting = -1; + const char *base = base_buf->buf; if (!ps || !ps->nr) return 1; diff --git a/tree-walk.h b/tree-walk.h index c12f0a2978..f81c232b5a 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } -extern int tree_entry_interesting(const struct name_entry *, const char *, int, const struct pathspec *ps); +extern int tree_entry_interesting(const struct name_entry *, const struct strbuf *, const struct pathspec *ps); #endif From 1ebdd91583c8d72c51c42e38aa0dde3bf8ae809e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:43 +0700 Subject: [PATCH 1499/3720] tree_entry_interesting(): refactor into separate smaller functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- tree-walk.c | 170 ++++++++++++++++++++++++++++------------------------ 1 file changed, 93 insertions(+), 77 deletions(-) diff --git a/tree-walk.c b/tree-walk.c index 0830676492..5012705346 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -456,6 +456,90 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch return retval; } +static int match_entry(const struct name_entry *entry, int pathlen, + const char *match, int matchlen, + int *never_interesting) +{ + int m = -1; /* signals that we haven't called strncmp() */ + + if (*never_interesting) { + /* + * We have not seen any match that sorts later + * than the current path. + */ + + /* + * Does match sort strictly earlier than path + * with their common parts? + */ + m = strncmp(match, entry->path, + (matchlen < pathlen) ? matchlen : pathlen); + if (m < 0) + return 0; + + /* + * If we come here even once, that means there is at + * least one pathspec that would sort equal to or + * later than the path we are currently looking at. + * In other words, if we have never reached this point + * after iterating all pathspecs, it means all + * pathspecs are either outside of base, or inside the + * base but sorts strictly earlier than the current + * one. In either case, they will never match the + * subsequent entries. In such a case, we initialized + * the variable to -1 and that is what will be + * returned, allowing the caller to terminate early. + */ + *never_interesting = 0; + } + + if (pathlen > matchlen) + return 0; + + if (matchlen > pathlen) { + if (match[pathlen] != '/') + return 0; + if (!S_ISDIR(entry->mode)) + return 0; + } + + if (m == -1) + /* + * we cheated and did not do strncmp(), so we do + * that here. + */ + m = strncmp(match, entry->path, pathlen); + + /* + * If common part matched earlier then it is a hit, + * because we rejected the case where path is not a + * leading directory and is shorter than match. + */ + if (!m) + return 1; + + return 0; +} + +static int match_dir_prefix(const char *base, int baselen, + const char *match, int matchlen) +{ + if (strncmp(base, match, matchlen)) + return 0; + + /* + * If the base is a subdirectory of a path which + * was specified, all of them are interesting. + */ + if (!matchlen || + base[matchlen] == '/' || + match[matchlen - 1] == '/') + return 1; + + /* Just a random prefix match */ + return 0; +} + /* * Is a tree entry interesting given the pathspec we have? * @@ -466,13 +550,12 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch * - negative for "no, and no subsequent entries will be either" */ int tree_entry_interesting(const struct name_entry *entry, - const struct strbuf *base_buf, + const struct strbuf *base, const struct pathspec *ps) { int i; - int pathlen, baselen = base_buf->len; + int pathlen, baselen = base->len; int never_interesting = -1; - const char *base = base_buf->buf; if (!ps || !ps->nr) return 1; @@ -483,88 +566,21 @@ int tree_entry_interesting(const struct name_entry *entry, const struct pathspec_item *item = ps->items+i; const char *match = item->match; int matchlen = item->len; - int m = -1; /* signals that we haven't called strncmp() */ if (baselen >= matchlen) { /* If it doesn't match, move along... */ - if (strncmp(base, match, matchlen)) + if (!match_dir_prefix(base->buf, baselen, match, matchlen)) continue; - - /* - * If the base is a subdirectory of a path which - * was specified, all of them are interesting. - */ - if (!matchlen || - base[matchlen] == '/' || - match[matchlen - 1] == '/') - return 2; - - /* Just a random prefix match */ - continue; + return 2; } /* Does the base match? */ - if (strncmp(base, match, baselen)) - continue; - - match += baselen; - matchlen -= baselen; - - if (never_interesting) { - /* - * We have not seen any match that sorts later - * than the current path. - */ - - /* - * Does match sort strictly earlier than path - * with their common parts? - */ - m = strncmp(match, entry->path, - (matchlen < pathlen) ? matchlen : pathlen); - if (m < 0) - continue; - - /* - * If we come here even once, that means there is at - * least one pathspec that would sort equal to or - * later than the path we are currently looking at. - * In other words, if we have never reached this point - * after iterating all pathspecs, it means all - * pathspecs are either outside of base, or inside the - * base but sorts strictly earlier than the current - * one. In either case, they will never match the - * subsequent entries. In such a case, we initialized - * the variable to -1 and that is what will be - * returned, allowing the caller to terminate early. - */ - never_interesting = 0; + if (!strncmp(base->buf, match, baselen)) { + if (match_entry(entry, pathlen, + match + baselen, matchlen - baselen, + &never_interesting)) + return 1; } - - if (pathlen > matchlen) - continue; - - if (matchlen > pathlen) { - if (match[pathlen] != '/') - continue; - if (!S_ISDIR(entry->mode)) - continue; - } - - if (m == -1) - /* - * we cheated and did not do strncmp(), so we do - * that here. - */ - m = strncmp(match, entry->path, pathlen); - - /* - * If common part matched earlier then it is a hit, - * because we rejected the case where path is not a - * leading directory and is shorter than match. - */ - if (!m) - return 1; } return never_interesting; /* No matches */ } From c4dc9d4de6cc709cba565c15ffc2603fd9206903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:44 +0700 Subject: [PATCH 1500/3720] tree_entry_interesting(): support depth limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is needed to replace pathspec_matches() in builtin/grep.c. max_depth == -1 means infinite depth. Depth limit is only effective when pathspec.recursive == 1. When pathspec.recursive == 0, the behavior depends on match functions: non-recursive for tree_entry_interesting() and recursive for match_pathspec{,_depth} Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- cache.h | 2 ++ dir.c | 15 +++++++++++++++ dir.h | 1 + tree-diff.c | 4 ++++ tree-walk.c | 19 ++++++++++++++++--- 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/cache.h b/cache.h index 9eeecc2e88..b110775bf3 100644 --- a/cache.h +++ b/cache.h @@ -496,6 +496,8 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct struct pathspec { const char **raw; /* get_pathspec() result, not freed by free_pathspec() */ int nr; + int recursive:1; + int max_depth; struct pathspec_item { const char *match; int len; diff --git a/dir.c b/dir.c index a88f2ef1a4..79e88f6b9f 100644 --- a/dir.c +++ b/dir.c @@ -71,6 +71,21 @@ int fill_directory(struct dir_struct *dir, const char **pathspec) return len; } +int within_depth(const char *name, int namelen, + int depth, int max_depth) +{ + const char *cp = name, *cpe = name + namelen; + + while (cp < cpe) { + if (*cp++ != '/') + continue; + depth++; + if (depth > max_depth) + return 0; + } + return 1; +} + /* * Does 'match' match the given name? * A match is found if diff --git a/dir.h b/dir.h index 278d84cdf7..c71de086f0 100644 --- a/dir.h +++ b/dir.h @@ -65,6 +65,7 @@ struct dir_struct { #define MATCHED_FNMATCH 2 #define MATCHED_EXACTLY 3 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen); +extern int within_depth(const char *name, int namelen, int depth, int max_depth); extern int fill_directory(struct dir_struct *dir, const char **pathspec); extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec); diff --git a/tree-diff.c b/tree-diff.c index f8772c9142..0887752f29 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -152,6 +152,10 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, struct strbuf base; int baselen = strlen(base_str); + /* Enable recursion indefinitely */ + opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE); + opt->pathspec.max_depth = -1; + strbuf_init(&base, PATH_MAX); strbuf_add(&base, base_str, baselen); diff --git a/tree-walk.c b/tree-walk.c index 5012705346..91d7b36567 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -1,6 +1,7 @@ #include "cache.h" #include "tree-walk.h" #include "unpack-trees.h" +#include "dir.h" #include "tree.h" static const char *get_mode(const char *str, unsigned int *modep) @@ -557,8 +558,13 @@ int tree_entry_interesting(const struct name_entry *entry, int pathlen, baselen = base->len; int never_interesting = -1; - if (!ps || !ps->nr) - return 1; + if (!ps->nr) { + if (!ps->recursive || ps->max_depth == -1) + return 1; + return !!within_depth(base->buf, baselen, + !!S_ISDIR(entry->mode), + ps->max_depth); + } pathlen = tree_entry_len(entry->path, entry->sha1); @@ -571,7 +577,14 @@ int tree_entry_interesting(const struct name_entry *entry, /* If it doesn't match, move along... */ if (!match_dir_prefix(base->buf, baselen, match, matchlen)) continue; - return 2; + + if (!ps->recursive || ps->max_depth == -1) + return 2; + + return !!within_depth(base->buf + matchlen + 1, + baselen - matchlen - 1, + !!S_ISDIR(entry->mode), + ps->max_depth); } /* Does the base match? */ From 9d7d10ef7b23518c8fa8b683b5d8dc9c3641b61c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:45 +0700 Subject: [PATCH 1501/3720] tree_entry_interesting(): fix depth limit with overlapping pathspecs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suppose we have two pathspecs 'a' and 'a/b' (both are dirs) and depth limit 1. In current code, pathspecs are checked in input order. When 'a/b' is checked against pathspec 'a', it fails depth limit and therefore is excluded, although it should match 'a/b' pathspec. This patch reorders all pathspecs alphabetically, then teaches tree_entry_interesting() to check against the deepest pathspec first, so depth limit of a shallower pathspec won't affect a deeper one. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- dir.c | 13 +++++++++++++ tree-walk.c | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/dir.c b/dir.c index 79e88f6b9f..aa0522dc49 100644 --- a/dir.c +++ b/dir.c @@ -1086,6 +1086,15 @@ int remove_path(const char *name) return 0; } +static int pathspec_item_cmp(const void *a_, const void *b_) +{ + struct pathspec_item *a, *b; + + a = (struct pathspec_item *)a_; + b = (struct pathspec_item *)b_; + return strcmp(a->match, b->match); +} + int init_pathspec(struct pathspec *pathspec, const char **paths) { const char **p = paths; @@ -1109,6 +1118,10 @@ int init_pathspec(struct pathspec *pathspec, const char **paths) item->match = path; item->len = strlen(path); } + + qsort(pathspec->items, pathspec->nr, + sizeof(struct pathspec_item), pathspec_item_cmp); + return 0; } diff --git a/tree-walk.c b/tree-walk.c index 91d7b36567..93b05a7442 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -568,7 +568,7 @@ int tree_entry_interesting(const struct name_entry *entry, pathlen = tree_entry_len(entry->path, entry->sha1); - for (i = 0; i < ps->nr; i++) { + for (i = ps->nr-1; i >= 0; i--) { const struct pathspec_item *item = ps->items+i; const char *match = item->match; int matchlen = item->len; From e10cb0f7311f6131aa33855b6c41c8a2291ec635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:46 +0700 Subject: [PATCH 1502/3720] tree_entry_interesting(): support wildcard matching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit never_interesting optimization is disabled if there is any wildcard pathspec, even if it only matches exactly on trees. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- cache.h | 2 ++ dir.c | 3 +++ t/t4010-diff-pathspec.sh | 14 ++++++++++++++ tree-walk.c | 30 +++++++++++++++++++++++++++--- tree-walk.h | 2 +- 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/cache.h b/cache.h index b110775bf3..dc0bfb4d78 100644 --- a/cache.h +++ b/cache.h @@ -496,11 +496,13 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct struct pathspec { const char **raw; /* get_pathspec() result, not freed by free_pathspec() */ int nr; + int has_wildcard:1; int recursive:1; int max_depth; struct pathspec_item { const char *match; int len; + int has_wildcard:1; } *items; }; diff --git a/dir.c b/dir.c index aa0522dc49..66c163f4f5 100644 --- a/dir.c +++ b/dir.c @@ -1117,6 +1117,9 @@ int init_pathspec(struct pathspec *pathspec, const char **paths) item->match = path; item->len = strlen(path); + item->has_wildcard = !no_wildcard(path); + if (item->has_wildcard) + pathspec->has_wildcard = 1; } qsort(pathspec->items, pathspec->nr, diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index 94df7ae53a..4b120f8e23 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -70,4 +70,18 @@ test_expect_success 'diff-tree pathspec' ' test_cmp expected current ' +EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + +test_expect_success 'diff-tree with wildcard shows dir also matches' ' + git diff-tree --name-only $EMPTY_TREE $tree -- "f*" >result && + echo file0 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard' ' + git diff-tree -r --name-only $EMPTY_TREE $tree -- "*file1" >result && + echo path1/file1 >expected && + test_cmp expected result +' + test_done diff --git a/tree-walk.c b/tree-walk.c index 93b05a7442..cc5a4e1f44 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -551,12 +551,12 @@ static int match_dir_prefix(const char *base, int baselen, * - negative for "no, and no subsequent entries will be either" */ int tree_entry_interesting(const struct name_entry *entry, - const struct strbuf *base, + struct strbuf *base, const struct pathspec *ps) { int i; int pathlen, baselen = base->len; - int never_interesting = -1; + int never_interesting = ps->has_wildcard ? 0 : -1; if (!ps->nr) { if (!ps->recursive || ps->max_depth == -1) @@ -576,7 +576,7 @@ int tree_entry_interesting(const struct name_entry *entry, if (baselen >= matchlen) { /* If it doesn't match, move along... */ if (!match_dir_prefix(base->buf, baselen, match, matchlen)) - continue; + goto match_wildcards; if (!ps->recursive || ps->max_depth == -1) return 2; @@ -594,6 +594,30 @@ int tree_entry_interesting(const struct name_entry *entry, &never_interesting)) return 1; } + +match_wildcards: + if (!ps->items[i].has_wildcard) + continue; + + /* + * Concatenate base and entry->path into one and do + * fnmatch() on it. + */ + + strbuf_add(base, entry->path, pathlen); + + if (!fnmatch(match, base->buf, 0)) { + strbuf_setlen(base, baselen); + return 1; + } + strbuf_setlen(base, baselen); + + /* + * Match all directories. We'll try to match files + * later on. + */ + if (ps->recursive && S_ISDIR(entry->mode)) + return 1; } return never_interesting; /* No matches */ } diff --git a/tree-walk.h b/tree-walk.h index f81c232b5a..6589ee27e4 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } -extern int tree_entry_interesting(const struct name_entry *, const struct strbuf *, const struct pathspec *ps); +extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, const struct pathspec *ps); #endif From b3d4b34ae6da6801da468e7fc7f01769972019f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:47 +0700 Subject: [PATCH 1503/3720] tree_entry_interesting(): optimize wildcard matching when base is matched MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If base is already matched, skip that part when calling fnmatch(). This happens quite often if users start a command from worktree's subdirectory and prefix is usually prepended to all pathspecs. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- t/t4010-diff-pathspec.sh | 18 ++++++++++++++++++ tree-walk.c | 14 ++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index 4b120f8e23..fbc8cd8f05 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -84,4 +84,22 @@ test_expect_success 'diff-tree -r with wildcard' ' test_cmp expected result ' +test_expect_success 'diff-tree with wildcard shows dir also matches' ' + git diff-tree --name-only $tree $tree2 -- "path1/f*" >result && + echo path1 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard from beginning' ' + git diff-tree -r --name-only $tree $tree2 -- "path1/*file1" >result && + echo path1/file1 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard' ' + git diff-tree -r --name-only $tree $tree2 -- "path1/f*" >result && + echo path1/file1 >expected && + test_cmp expected result +' + test_done diff --git a/tree-walk.c b/tree-walk.c index cc5a4e1f44..99413b379e 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -593,6 +593,20 @@ int tree_entry_interesting(const struct name_entry *entry, match + baselen, matchlen - baselen, &never_interesting)) return 1; + + if (ps->items[i].has_wildcard) { + if (!fnmatch(match + baselen, entry->path, 0)) + return 1; + + /* + * Match all directories. We'll try to + * match files later on. + */ + if (ps->recursive && S_ISDIR(entry->mode)) + return 1; + } + + continue; } match_wildcards: From a2a1da847d9011497182e9c286734733f03a8b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:48 +0700 Subject: [PATCH 1504/3720] pathspec: add match_pathspec_depth() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit match_pathspec_depth() is a clone of match_pathspec() except that it can take depth limit. Computation is a bit lighter compared to match_pathspec() because it's usually precomputed and stored in struct pathspec. In long term, match_pathspec() and match_one() should be removed in favor of this function. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- dir.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dir.h | 3 ++ 2 files changed, 92 insertions(+) diff --git a/dir.c b/dir.c index 66c163f4f5..b1407a5dc9 100644 --- a/dir.c +++ b/dir.c @@ -169,6 +169,95 @@ int match_pathspec(const char **pathspec, const char *name, int namelen, return retval; } +/* + * Does 'match' match the given name? + * A match is found if + * + * (1) the 'match' string is leading directory of 'name', or + * (2) the 'match' string is a wildcard and matches 'name', or + * (3) the 'match' string is exactly the same as 'name'. + * + * and the return value tells which case it was. + * + * It returns 0 when there is no match. + */ +static int match_pathspec_item(const struct pathspec_item *item, int prefix, + const char *name, int namelen) +{ + /* name/namelen has prefix cut off by caller */ + const char *match = item->match + prefix; + int matchlen = item->len - prefix; + + /* If the match was just the prefix, we matched */ + if (!*match) + return MATCHED_RECURSIVELY; + + if (matchlen <= namelen && !strncmp(match, name, matchlen)) { + if (matchlen == namelen) + return MATCHED_EXACTLY; + + if (match[matchlen-1] == '/' || name[matchlen] == '/') + return MATCHED_RECURSIVELY; + } + + if (item->has_wildcard && !fnmatch(match, name, 0)) + return MATCHED_FNMATCH; + + return 0; +} + +/* + * Given a name and a list of pathspecs, see if the name matches + * any of the pathspecs. The caller is also interested in seeing + * all pathspec matches some names it calls this function with + * (otherwise the user could have mistyped the unmatched pathspec), + * and a mark is left in seen[] array for pathspec element that + * actually matched anything. + */ +int match_pathspec_depth(const struct pathspec *ps, + const char *name, int namelen, + int prefix, char *seen) +{ + int i, retval = 0; + + if (!ps->nr) { + if (!ps->recursive || ps->max_depth == -1) + return MATCHED_RECURSIVELY; + + if (within_depth(name, namelen, 0, ps->max_depth)) + return MATCHED_EXACTLY; + else + return 0; + } + + name += prefix; + namelen -= prefix; + + for (i = ps->nr - 1; i >= 0; i--) { + int how; + if (seen && seen[i] == MATCHED_EXACTLY) + continue; + how = match_pathspec_item(ps->items+i, prefix, name, namelen); + if (ps->recursive && ps->max_depth != -1 && + how && how != MATCHED_FNMATCH) { + int len = ps->items[i].len; + if (name[len] == '/') + len++; + if (within_depth(name+len, namelen-len, 0, ps->max_depth)) + how = MATCHED_EXACTLY; + else + how = 0; + } + if (how) { + if (retval < how) + retval = how; + if (seen && seen[i] < how) + seen[i] = how; + } + } + return retval; +} + static int no_wildcard(const char *string) { return string[strcspn(string, "*?[{\\")] == '\0'; diff --git a/dir.h b/dir.h index c71de086f0..ddb41473cd 100644 --- a/dir.h +++ b/dir.h @@ -65,6 +65,9 @@ struct dir_struct { #define MATCHED_FNMATCH 2 #define MATCHED_EXACTLY 3 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen); +extern int match_pathspec_depth(const struct pathspec *pathspec, + const char *name, int namelen, + int prefix, char *seen); extern int within_depth(const char *name, int namelen, int depth, int max_depth); extern int fill_directory(struct dir_struct *dir, const char **pathspec); From ec56c4d81dab595236d51a10f910e5aa0ee78cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 17 Dec 2010 19:43:06 +0700 Subject: [PATCH 1505/3720] struct rev_info: convert prune_data to struct pathspec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/add.c | 2 +- builtin/diff.c | 12 ++++-------- builtin/fast-export.c | 2 +- diff-lib.c | 6 +++--- revision.c | 15 ++++++++------- revision.h | 2 +- wt-status.c | 4 ++-- 7 files changed, 20 insertions(+), 23 deletions(-) diff --git a/builtin/add.c b/builtin/add.c index 56a4e0af6b..3fc79a5d3f 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -86,7 +86,7 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags) struct rev_info rev; init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); - rev.prune_data = pathspec; + init_pathspec(&rev.prune_data, pathspec); rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = update_callback; data.flags = flags; diff --git a/builtin/diff.c b/builtin/diff.c index 76c42d834f..4ebb1b65f4 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -371,14 +371,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } die("unhandled object '%s' given.", name); } - if (rev.prune_data) { - const char **pathspec = rev.prune_data; - while (*pathspec) { - if (!path) - path = *pathspec; - paths++; - pathspec++; - } + if (rev.prune_data.nr) { + if (!path) + path = rev.prune_data.items[0].match; + paths += rev.prune_data.nr; } /* diff --git a/builtin/fast-export.c b/builtin/fast-export.c index c8fd46b872..ba57457cc5 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -651,7 +651,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) if (import_filename) import_marks(import_filename); - if (import_filename && revs.prune_data) + if (import_filename && revs.prune_data.nr) full_tree = 1; get_tags_and_duplicates(&revs.pending, &extra_refs); diff --git a/diff-lib.c b/diff-lib.c index 3b809f2e0d..2251f3df68 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -106,7 +106,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) break; - if (!ce_path_match(ce, revs->prune_data)) + if (!ce_path_match(ce, revs->prune_data.raw)) continue; if (ce_stage(ce)) { @@ -427,7 +427,7 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o) if (tree == o->df_conflict_entry) tree = NULL; - if (ce_path_match(idx ? idx : tree, revs->prune_data)) + if (ce_path_match(idx ? idx : tree, revs->prune_data.raw)) do_oneway_diff(o, idx, tree); return 0; @@ -501,7 +501,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) active_nr = dst - active_cache; init_revisions(&revs, NULL); - revs.prune_data = opt->pathspec.raw; + init_pathspec(&revs.prune_data, opt->pathspec.raw); tree = parse_tree_indirect(tree_sha1); if (!tree) die("bad tree object %s", sha1_to_hex(tree_sha1)); diff --git a/revision.c b/revision.c index b2a5867dcd..515e2dd23b 100644 --- a/revision.c +++ b/revision.c @@ -323,7 +323,7 @@ static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct * tagged commit by specifying both --simplify-by-decoration * and pathspec. */ - if (!revs->prune_data) + if (!revs->prune_data.nr) return REV_TREE_SAME; } @@ -969,7 +969,7 @@ static void prepare_show_merge(struct rev_info *revs) struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; - if (ce_path_match(ce, revs->prune_data)) { + if (ce_path_match(ce, revs->prune_data.raw)) { prune_num++; prune = xrealloc(prune, sizeof(*prune) * prune_num); prune[prune_num-2] = ce->name; @@ -979,7 +979,8 @@ static void prepare_show_merge(struct rev_info *revs) ce_same_name(ce, active_cache[i+1])) i++; } - revs->prune_data = prune; + free_pathspec(&revs->prune_data); + init_pathspec(&revs->prune_data, prune); revs->limited = 1; } @@ -1616,7 +1617,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s } if (prune_data) - revs->prune_data = get_pathspec(revs->prefix, prune_data); + init_pathspec(&revs->prune_data, get_pathspec(revs->prefix, prune_data)); if (revs->def == NULL) revs->def = opt ? opt->def : NULL; @@ -1647,13 +1648,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->topo_order) revs->limited = 1; - if (revs->prune_data) { - diff_tree_setup_paths(revs->prune_data, &revs->pruning); + if (revs->prune_data.nr) { + diff_tree_setup_paths(revs->prune_data.raw, &revs->pruning); /* Can't prune commits with rename following: the paths change.. */ if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES)) revs->prune = 1; if (!revs->full_diff) - diff_tree_setup_paths(revs->prune_data, &revs->diffopt); + diff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt); } if (revs->combine_merges) revs->ignore_merges = 0; diff --git a/revision.h b/revision.h index 05659c64ac..82509dd1d9 100644 --- a/revision.h +++ b/revision.h @@ -34,7 +34,7 @@ struct rev_info { /* Basic information */ const char *prefix; const char *def; - void *prune_data; + struct pathspec prune_data; unsigned int early_output; /* Traversal flags */ diff --git a/wt-status.c b/wt-status.c index 54b6b03b9c..5c6b11849b 100644 --- a/wt-status.c +++ b/wt-status.c @@ -319,7 +319,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s) } rev.diffopt.format_callback = wt_status_collect_changed_cb; rev.diffopt.format_callback_data = s; - rev.prune_data = s->pathspec; + init_pathspec(&rev.prune_data, s->pathspec); run_diff_files(&rev, 0); } @@ -344,7 +344,7 @@ static void wt_status_collect_changes_index(struct wt_status *s) rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 200; rev.diffopt.break_opt = 0; - rev.prune_data = s->pathspec; + init_pathspec(&rev.prune_data, s->pathspec); run_diff_index(&rev, 1); } From 39b99a26cfc885db291a088c1cb67ac8aedba37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 17 Dec 2010 19:43:07 +0700 Subject: [PATCH 1506/3720] Convert ce_path_match() to use struct pathspec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/update-index.c | 8 ++++++-- cache.h | 2 +- diff-lib.c | 4 ++-- preload-index.c | 5 ++++- read-cache.c | 7 ++++--- revision.c | 2 +- wt-status.c | 5 ++++- 7 files changed, 22 insertions(+), 11 deletions(-) diff --git a/builtin/update-index.c b/builtin/update-index.c index 3ab214d24e..9d1f67e64c 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -543,7 +543,10 @@ static int do_reupdate(int ac, const char **av, */ int pos; int has_head = 1; - const char **pathspec = get_pathspec(prefix, av + 1); + const char **paths = get_pathspec(prefix, av + 1); + struct pathspec pathspec; + + init_pathspec(&pathspec, paths); if (read_ref("HEAD", head_sha1)) /* If there is no HEAD, that means it is an initial @@ -556,7 +559,7 @@ static int do_reupdate(int ac, const char **av, struct cache_entry *old = NULL; int save_nr; - if (ce_stage(ce) || !ce_path_match(ce, pathspec)) + if (ce_stage(ce) || !ce_path_match(ce, &pathspec)) continue; if (has_head) old = read_one_ent(NULL, head_sha1, @@ -575,6 +578,7 @@ static int do_reupdate(int ac, const char **av, if (save_nr != active_nr) goto redo; } + free_pathspec(&pathspec); return 0; } diff --git a/cache.h b/cache.h index dc0bfb4d78..b5cd61c083 100644 --- a/cache.h +++ b/cache.h @@ -508,7 +508,7 @@ struct pathspec { extern int init_pathspec(struct pathspec *, const char **); extern void free_pathspec(struct pathspec *); -extern int ce_path_match(const struct cache_entry *ce, const char **pathspec); +extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec); extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); diff --git a/diff-lib.c b/diff-lib.c index 2251f3df68..1e22992cb1 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -106,7 +106,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) break; - if (!ce_path_match(ce, revs->prune_data.raw)) + if (!ce_path_match(ce, &revs->prune_data)) continue; if (ce_stage(ce)) { @@ -427,7 +427,7 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o) if (tree == o->df_conflict_entry) tree = NULL; - if (ce_path_match(idx ? idx : tree, revs->prune_data.raw)) + if (ce_path_match(idx ? idx : tree, &revs->prune_data)) do_oneway_diff(o, idx, tree); return 0; diff --git a/preload-index.c b/preload-index.c index e3d0bda31a..49cb08df96 100644 --- a/preload-index.c +++ b/preload-index.c @@ -35,7 +35,9 @@ static void *preload_thread(void *_data) struct index_state *index = p->index; struct cache_entry **cep = index->cache + p->offset; struct cache_def cache; + struct pathspec pathspec; + init_pathspec(&pathspec, p->pathspec); memset(&cache, 0, sizeof(cache)); nr = p->nr; if (nr + p->offset > index->cache_nr) @@ -51,7 +53,7 @@ static void *preload_thread(void *_data) continue; if (ce_uptodate(ce)) continue; - if (!ce_path_match(ce, p->pathspec)) + if (!ce_path_match(ce, &pathspec)) continue; if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce))) continue; @@ -61,6 +63,7 @@ static void *preload_thread(void *_data) continue; ce_mark_uptodate(ce); } while (--nr > 0); + free_pathspec(&pathspec); return NULL; } diff --git a/read-cache.c b/read-cache.c index 1f42473e80..f1141a36d8 100644 --- a/read-cache.c +++ b/read-cache.c @@ -683,17 +683,18 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b) return ce_namelen(b) == len && !memcmp(a->name, b->name, len); } -int ce_path_match(const struct cache_entry *ce, const char **pathspec) +int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec) { const char *match, *name; + const char **ps = pathspec->raw; int len; - if (!pathspec) + if (!pathspec->nr) return 1; len = ce_namelen(ce); name = ce->name; - while ((match = *pathspec++) != NULL) { + while ((match = *ps++) != NULL) { int matchlen = strlen(match); if (matchlen > len) continue; diff --git a/revision.c b/revision.c index 515e2dd23b..a0d3816239 100644 --- a/revision.c +++ b/revision.c @@ -969,7 +969,7 @@ static void prepare_show_merge(struct rev_info *revs) struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; - if (ce_path_match(ce, revs->prune_data.raw)) { + if (ce_path_match(ce, &revs->prune_data)) { prune_num++; prune = xrealloc(prune, sizeof(*prune) * prune_num); prune[prune_num-2] = ce->name; diff --git a/wt-status.c b/wt-status.c index 5c6b11849b..457d265f86 100644 --- a/wt-status.c +++ b/wt-status.c @@ -350,14 +350,16 @@ static void wt_status_collect_changes_index(struct wt_status *s) static void wt_status_collect_changes_initial(struct wt_status *s) { + struct pathspec pathspec; int i; + init_pathspec(&pathspec, s->pathspec); for (i = 0; i < active_nr; i++) { struct string_list_item *it; struct wt_status_change_data *d; struct cache_entry *ce = active_cache[i]; - if (!ce_path_match(ce, s->pathspec)) + if (!ce_path_match(ce, &pathspec)) continue; it = string_list_insert(&s->change, ce->name); d = it->util; @@ -372,6 +374,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s) else d->index_status = DIFF_STATUS_ADDED; } + free_pathspec(&pathspec); } static void wt_status_collect_untracked(struct wt_status *s) From 24649aaffc5f494f1660d1d59a69b22f46b14a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:50 +0700 Subject: [PATCH 1507/3720] Convert ce_path_match() to use match_pathspec_depth() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- read-cache.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/read-cache.c b/read-cache.c index f1141a36d8..7f51cd6a65 100644 --- a/read-cache.c +++ b/read-cache.c @@ -685,29 +685,7 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b) int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec) { - const char *match, *name; - const char **ps = pathspec->raw; - int len; - - if (!pathspec->nr) - return 1; - - len = ce_namelen(ce); - name = ce->name; - while ((match = *ps++) != NULL) { - int matchlen = strlen(match); - if (matchlen > len) - continue; - if (memcmp(name, match, matchlen)) - continue; - if (matchlen && name[matchlen-1] == '/') - return 1; - if (name[matchlen] == '/' || !name[matchlen]) - return 1; - if (!matchlen) - return 1; - } - return 0; + return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL); } /* From 4c117786da6f1dc67bd192ceabfd382bd64f128f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:51 +0700 Subject: [PATCH 1508/3720] grep: convert to use struct pathspec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/grep.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index da32f3df34..4179af8a44 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -585,7 +585,7 @@ static void run_pager(struct grep_opt *opt, const char *prefix) free(argv); } -static int grep_cache(struct grep_opt *opt, const char **paths, int cached) +static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached) { int hit = 0; int nr; @@ -595,7 +595,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) struct cache_entry *ce = active_cache[nr]; if (!S_ISREG(ce->ce_mode)) continue; - if (!pathspec_matches(paths, ce->name, opt->max_depth)) + if (!pathspec_matches(pathspec->raw, ce->name, opt->max_depth)) continue; /* * If CE_VALID is on, we assume worktree file and its cache entry @@ -622,7 +622,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) return hit; } -static int grep_tree(struct grep_opt *opt, const char **paths, +static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, const char *tree_name, const char *base) { @@ -656,7 +656,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths, strbuf_addch(&pathbuf, '/'); down = pathbuf.buf + tn_len; - if (!pathspec_matches(paths, down, opt->max_depth)) + if (!pathspec_matches(pathspec->raw, down, opt->max_depth)) ; else if (S_ISREG(entry.mode)) hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len); @@ -671,7 +671,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths, die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); init_tree_desc(&sub, data, size); - hit |= grep_tree(opt, paths, &sub, tree_name, down); + hit |= grep_tree(opt, pathspec, &sub, tree_name, down); free(data); } if (hit && opt->status_only) @@ -681,7 +681,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths, return hit; } -static int grep_object(struct grep_opt *opt, const char **paths, +static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct object *obj, const char *name) { if (obj->type == OBJ_BLOB) @@ -696,14 +696,14 @@ static int grep_object(struct grep_opt *opt, const char **paths, if (!data) die("unable to read tree (%s)", sha1_to_hex(obj->sha1)); init_tree_desc(&tree, data, size); - hit = grep_tree(opt, paths, &tree, name, ""); + hit = grep_tree(opt, pathspec, &tree, name, ""); free(data); return hit; } die("unable to grep from object of type %s", typename(obj->type)); } -static int grep_objects(struct grep_opt *opt, const char **paths, +static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, const struct object_array *list) { unsigned int i; @@ -713,7 +713,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths, for (i = 0; i < nr; i++) { struct object *real_obj; real_obj = deref_tag(list->objects[i].item, NULL, 0); - if (grep_object(opt, paths, real_obj, list->objects[i].name)) { + if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) { hit = 1; if (opt->status_only) break; @@ -722,7 +722,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths, return hit; } -static int grep_directory(struct grep_opt *opt, const char **paths) +static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec) { struct dir_struct dir; int i, hit = 0; @@ -730,7 +730,7 @@ static int grep_directory(struct grep_opt *opt, const char **paths) memset(&dir, 0, sizeof(dir)); setup_standard_excludes(&dir); - fill_directory(&dir, paths); + fill_directory(&dir, pathspec->raw); for (i = 0; i < dir.nr; i++) { hit |= grep_file(opt, dir.entries[i]->name); if (hit && opt->status_only) @@ -836,6 +836,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) struct grep_opt opt; struct object_array list = OBJECT_ARRAY_INIT; const char **paths = NULL; + struct pathspec pathspec; struct string_list path_list = STRING_LIST_INIT_NODUP; int i; int dummy; @@ -1063,6 +1064,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) paths[0] = prefix; paths[1] = NULL; } + init_pathspec(&pathspec, paths); if (show_in_pager && (cached || list.nr)) die("--open-files-in-pager only works on the worktree"); @@ -1093,16 +1095,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix) die("--cached cannot be used with --no-index."); if (list.nr) die("--no-index cannot be used with revs."); - hit = grep_directory(&opt, paths); + hit = grep_directory(&opt, &pathspec); } else if (!list.nr) { if (!cached) setup_work_tree(); - hit = grep_cache(&opt, paths, cached); + hit = grep_cache(&opt, &pathspec, cached); } else { if (cached) die("both --cached and trees are given."); - hit = grep_objects(&opt, paths, &list); + hit = grep_objects(&opt, &pathspec, &list); } if (use_threads) From 06e3e10950659f05ec94208e32471c24ceae0229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:52 +0700 Subject: [PATCH 1509/3720] grep: use match_pathspec_depth() for cache/worktree grepping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index 4179af8a44..fbc7d02dbe 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -595,7 +595,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int struct cache_entry *ce = active_cache[nr]; if (!S_ISREG(ce->ce_mode)) continue; - if (!pathspec_matches(pathspec->raw, ce->name, opt->max_depth)) + if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; /* * If CE_VALID is on, we assume worktree file and its cache entry From 308db24c2c2cb92cc51a26b1a1f78bce7fe6576f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 17 Dec 2010 19:44:25 +0700 Subject: [PATCH 1510/3720] grep: use writable strbuf from caller for grep_tree() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/grep.c | 51 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index fbc7d02dbe..fa1ad28eea 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -623,43 +623,29 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int } static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, - struct tree_desc *tree, - const char *tree_name, const char *base) + struct tree_desc *tree, struct strbuf *base, int tn_len) { - int len; int hit = 0; struct name_entry entry; - char *down; - int tn_len = strlen(tree_name); - struct strbuf pathbuf; - - strbuf_init(&pathbuf, PATH_MAX + tn_len); - - if (tn_len) { - strbuf_add(&pathbuf, tree_name, tn_len); - strbuf_addch(&pathbuf, ':'); - tn_len = pathbuf.len; - } - strbuf_addstr(&pathbuf, base); - len = pathbuf.len; + int old_baselen = base->len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); - pathbuf.len = len; - strbuf_add(&pathbuf, entry.path, te_len); + + strbuf_add(base, entry.path, te_len); if (S_ISDIR(entry.mode)) /* Match "abc/" against pathspec to * decide if we want to descend into "abc" * directory. */ - strbuf_addch(&pathbuf, '/'); + strbuf_addch(base, '/'); - down = pathbuf.buf + tn_len; - if (!pathspec_matches(pathspec->raw, down, opt->max_depth)) + if (!pathspec_matches(pathspec->raw, base->buf + tn_len, opt->max_depth)) ; - else if (S_ISREG(entry.mode)) - hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len); + else if (S_ISREG(entry.mode)) { + hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len); + } else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; @@ -671,13 +657,14 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); init_tree_desc(&sub, data, size); - hit |= grep_tree(opt, pathspec, &sub, tree_name, down); + hit |= grep_tree(opt, pathspec, &sub, base, tn_len); free(data); } + strbuf_setlen(base, old_baselen); + if (hit && opt->status_only) break; } - strbuf_release(&pathbuf); return hit; } @@ -690,13 +677,23 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc tree; void *data; unsigned long size; - int hit; + struct strbuf base; + int hit, len; + data = read_object_with_reference(obj->sha1, tree_type, &size, NULL); if (!data) die("unable to read tree (%s)", sha1_to_hex(obj->sha1)); + + len = name ? strlen(name) : 0; + strbuf_init(&base, PATH_MAX + len + 1); + if (len) { + strbuf_add(&base, name, len); + strbuf_addch(&base, ':'); + } init_tree_desc(&tree, data, size); - hit = grep_tree(opt, pathspec, &tree, name, ""); + hit = grep_tree(opt, pathspec, &tree, &base, base.len); + strbuf_release(&base); free(data); return hit; } From 28cf7e3c434edf41e8b3cf79a195c681088bb9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 17 Dec 2010 19:45:33 +0700 Subject: [PATCH 1511/3720] grep: drop pathspec_matches() in favor of tree_entry_interesting() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/grep.c | 125 ++++++------------------------------------------- tree-diff.c | 4 +- tree-walk.c | 19 ++++---- tree-walk.h | 2 +- 4 files changed, 27 insertions(+), 123 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index fa1ad28eea..7256002902 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -333,106 +333,6 @@ static int grep_config(const char *var, const char *value, void *cb) return 0; } -/* - * Return non-zero if max_depth is negative or path has no more then max_depth - * slashes. - */ -static int accept_subdir(const char *path, int max_depth) -{ - if (max_depth < 0) - return 1; - - while ((path = strchr(path, '/')) != NULL) { - max_depth--; - if (max_depth < 0) - return 0; - path++; - } - return 1; -} - -/* - * Return non-zero if name is a subdirectory of match and is not too deep. - */ -static int is_subdir(const char *name, int namelen, - const char *match, int matchlen, int max_depth) -{ - if (matchlen > namelen || strncmp(name, match, matchlen)) - return 0; - - if (name[matchlen] == '\0') /* exact match */ - return 1; - - if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/') - return accept_subdir(name + matchlen + 1, max_depth); - - return 0; -} - -/* - * git grep pathspecs are somewhat different from diff-tree pathspecs; - * pathname wildcards are allowed. - */ -static int pathspec_matches(const char **paths, const char *name, int max_depth) -{ - int namelen, i; - if (!paths || !*paths) - return accept_subdir(name, max_depth); - namelen = strlen(name); - for (i = 0; paths[i]; i++) { - const char *match = paths[i]; - int matchlen = strlen(match); - const char *cp, *meta; - - if (is_subdir(name, namelen, match, matchlen, max_depth)) - return 1; - if (!fnmatch(match, name, 0)) - return 1; - if (name[namelen-1] != '/') - continue; - - /* We are being asked if the directory ("name") is worth - * descending into. - * - * Find the longest leading directory name that does - * not have metacharacter in the pathspec; the name - * we are looking at must overlap with that directory. - */ - for (cp = match, meta = NULL; cp - match < matchlen; cp++) { - char ch = *cp; - if (ch == '*' || ch == '[' || ch == '?') { - meta = cp; - break; - } - } - if (!meta) - meta = cp; /* fully literal */ - - if (namelen <= meta - match) { - /* Looking at "Documentation/" and - * the pattern says "Documentation/howto/", or - * "Documentation/diff*.txt". The name we - * have should match prefix. - */ - if (!memcmp(match, name, namelen)) - return 1; - continue; - } - - if (meta - match < namelen) { - /* Looking at "Documentation/howto/" and - * the pattern says "Documentation/h*"; - * match up to "Do.../h"; this avoids descending - * into "Documentation/technical/". - */ - if (!memcmp(match, name, meta - match)) - return 1; - continue; - } - } - return 0; -} - static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size) { void *data; @@ -625,25 +525,24 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, struct strbuf *base, int tn_len) { - int hit = 0; + int hit = 0, matched = 0; struct name_entry entry; int old_baselen = base->len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); + if (matched != 2) { + matched = tree_entry_interesting(&entry, base, tn_len, pathspec); + if (matched == -1) + break; /* no more matches */ + if (!matched) + continue; + } + strbuf_add(base, entry.path, te_len); - if (S_ISDIR(entry.mode)) - /* Match "abc/" against pathspec to - * decide if we want to descend into "abc" - * directory. - */ - strbuf_addch(base, '/'); - - if (!pathspec_matches(pathspec->raw, base->buf + tn_len, opt->max_depth)) - ; - else if (S_ISREG(entry.mode)) { + if (S_ISREG(entry.mode)) { hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len); } else if (S_ISDIR(entry.mode)) { @@ -656,6 +555,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); + + strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); hit |= grep_tree(opt, pathspec, &sub, base, tn_len); free(data); @@ -1062,6 +963,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) paths[1] = NULL; } init_pathspec(&pathspec, paths); + pathspec.max_depth = opt.max_depth; + pathspec.recursive = 1; if (show_in_pager && (cached || list.nr)) die("--open-files-in-pager only works on the worktree"); diff --git a/tree-diff.c b/tree-diff.c index 0887752f29..e27782c70e 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -72,7 +72,7 @@ static void show_tree(struct diff_options *opt, const char *prefix, if (all_interesting) show = 1; else { - show = tree_entry_interesting(&desc->entry, base, + show = tree_entry_interesting(&desc->entry, base, 0, &opt->pathspec); if (show == 2) all_interesting = 1; @@ -130,7 +130,7 @@ static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, if (all_interesting) show = 1; else { - show = tree_entry_interesting(&t->entry, base, + show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec); if (show == 2) all_interesting = 1; diff --git a/tree-walk.c b/tree-walk.c index 99413b379e..9b43ad58b5 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -551,17 +551,17 @@ static int match_dir_prefix(const char *base, int baselen, * - negative for "no, and no subsequent entries will be either" */ int tree_entry_interesting(const struct name_entry *entry, - struct strbuf *base, + struct strbuf *base, int base_offset, const struct pathspec *ps) { int i; - int pathlen, baselen = base->len; + int pathlen, baselen = base->len - base_offset; int never_interesting = ps->has_wildcard ? 0 : -1; if (!ps->nr) { if (!ps->recursive || ps->max_depth == -1) return 1; - return !!within_depth(base->buf, baselen, + return !!within_depth(base->buf + base_offset, baselen, !!S_ISDIR(entry->mode), ps->max_depth); } @@ -571,24 +571,25 @@ int tree_entry_interesting(const struct name_entry *entry, for (i = ps->nr-1; i >= 0; i--) { const struct pathspec_item *item = ps->items+i; const char *match = item->match; + const char *base_str = base->buf + base_offset; int matchlen = item->len; if (baselen >= matchlen) { /* If it doesn't match, move along... */ - if (!match_dir_prefix(base->buf, baselen, match, matchlen)) + if (!match_dir_prefix(base_str, baselen, match, matchlen)) goto match_wildcards; if (!ps->recursive || ps->max_depth == -1) return 2; - return !!within_depth(base->buf + matchlen + 1, + return !!within_depth(base_str + matchlen + 1, baselen - matchlen - 1, !!S_ISDIR(entry->mode), ps->max_depth); } /* Does the base match? */ - if (!strncmp(base->buf, match, baselen)) { + if (!strncmp(base_str, match, baselen)) { if (match_entry(entry, pathlen, match + baselen, matchlen - baselen, &never_interesting)) @@ -620,11 +621,11 @@ match_wildcards: strbuf_add(base, entry->path, pathlen); - if (!fnmatch(match, base->buf, 0)) { - strbuf_setlen(base, baselen); + if (!fnmatch(match, base->buf + base_offset, 0)) { + strbuf_setlen(base, base_offset + baselen); return 1; } - strbuf_setlen(base, baselen); + strbuf_setlen(base, base_offset + baselen); /* * Match all directories. We'll try to match files diff --git a/tree-walk.h b/tree-walk.h index 6589ee27e4..39524b7dba 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } -extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, const struct pathspec *ps); +extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps); #endif From ee47d9326448d290432ddedcc09e1058ef2893c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 15 Dec 2010 22:02:56 +0700 Subject: [PATCH 1512/3720] t7810: overlapping pathspecs and depth limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- t/t7810-grep.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 023f225a4b..d89faeebb3 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -182,6 +182,24 @@ do test_cmp expected actual ' + test_expect_success "grep --max-depth 0 -- . t $L" ' + { + echo ${HC}t/v:1:vvv + echo ${HC}v:1:vvv + } >expected && + git grep --max-depth 0 -n -e vvv $H -- . t >actual && + test_cmp expected actual + ' + + test_expect_success "grep --max-depth 0 -- t . $L" ' + { + echo ${HC}t/v:1:vvv + echo ${HC}v:1:vvv + } >expected && + git grep --max-depth 0 -n -e vvv $H -- t . >actual && + test_cmp expected actual + ' + done cat >expected < Date: Fri, 17 Dec 2010 20:26:47 +0700 Subject: [PATCH 1513/3720] Make rev-list --objects work together with pathspecs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When traversing commits, the selection of commits would heed the list of pathspecs passed, but subsequent walking of the trees of those commits would not. This resulted in 'rev-list --objects HEAD -- ' displaying objects at unwanted paths. Have process_tree() call tree_entry_interesting() to determine which paths are interesting and should be walked. Naturally, this change can provide a large speedup when paths are specified together with --objects, since many tree entries are now correctly ignored. Interestingly, though, this change also gives me a small (~1%) but repeatable speedup even when no paths are specified with --objects. Signed-off-by: Elijah Newren Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- list-objects.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/list-objects.c b/list-objects.c index 8953548c07..61f6cc98d9 100644 --- a/list-objects.c +++ b/list-objects.c @@ -61,12 +61,15 @@ static void process_tree(struct rev_info *revs, struct tree *tree, show_object_fn show, struct name_path *path, + struct strbuf *base, const char *name) { struct object *obj = &tree->object; struct tree_desc desc; struct name_entry entry; struct name_path me; + int all_interesting = (revs->diffopt.pathspec.nr == 0); + int baselen = base->len; if (!revs->tree_objects) return; @@ -82,13 +85,32 @@ static void process_tree(struct rev_info *revs, me.elem = name; me.elem_len = strlen(name); + if (!all_interesting) { + strbuf_addstr(base, name); + if (base->len) + strbuf_addch(base, '/'); + } + init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { + if (!all_interesting) { + int showit = tree_entry_interesting(&entry, + base, 0, + &revs->diffopt.pathspec); + + if (showit < 0) + break; + else if (!showit) + continue; + else if (showit == 2) + all_interesting = 1; + } + if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), - show, &me, entry.path); + show, &me, base, entry.path); else if (S_ISGITLINK(entry.mode)) process_gitlink(revs, entry.sha1, show, &me, entry.path); @@ -97,6 +119,7 @@ static void process_tree(struct rev_info *revs, lookup_blob(entry.sha1), show, &me, entry.path); } + strbuf_setlen(base, baselen); free(tree->buffer); tree->buffer = NULL; } @@ -146,7 +169,9 @@ void traverse_commit_list(struct rev_info *revs, { int i; struct commit *commit; + struct strbuf base; + strbuf_init(&base, PATH_MAX); while ((commit = get_revision(revs)) != NULL) { add_pending_tree(revs, commit->tree); show_commit(commit, data); @@ -164,7 +189,7 @@ void traverse_commit_list(struct rev_info *revs, } if (obj->type == OBJ_TREE) { process_tree(revs, (struct tree *)obj, show_object, - NULL, name); + NULL, &base, name); continue; } if (obj->type == OBJ_BLOB) { @@ -181,4 +206,5 @@ void traverse_commit_list(struct rev_info *revs, revs->pending.alloc = 0; revs->pending.objects = NULL; } + strbuf_release(&base); } From 4d475b5daf9633ac0cfc56566792bab243653043 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Mon, 20 Sep 2010 09:24:29 +1000 Subject: [PATCH 1514/3720] Add testcases showing how pathspecs are handled with rev-list --objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- t/t6000-rev-list-misc.sh | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100755 t/t6000-rev-list-misc.sh diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh new file mode 100755 index 0000000000..b10685af4e --- /dev/null +++ b/t/t6000-rev-list-misc.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +test_description='miscellaneous rev-list tests' + +. ./test-lib.sh + +test_expect_success setup ' + echo content1 >wanted_file && + echo content2 >unwanted_file && + git add wanted_file unwanted_file && + git commit -m one +' + +test_expect_success 'rev-list --objects heeds pathspecs' ' + git rev-list --objects HEAD -- wanted_file >output && + grep wanted_file output && + ! grep unwanted_file output +' + +test_expect_success 'rev-list --objects with pathspecs and deeper paths' ' + mkdir foo && + >foo/file && + git add foo/file && + git commit -m two && + + git rev-list --objects HEAD -- foo >output && + grep foo/file output && + + git rev-list --objects HEAD -- foo/file >output && + grep foo/file output && + ! grep unwanted_file output +' + +test_expect_success 'rev-list --objects with pathspecs and copied files' ' + git checkout --orphan junio-testcase && + git rm -rf . && + + mkdir two && + echo frotz >one && + cp one two/three && + git add one two/three && + test_tick && + git commit -m that && + + ONE=$(git rev-parse HEAD:one) + git rev-list --objects HEAD two >output && + grep "$ONE two/three" output && + ! grep one output +' + +test_done From ddad04efbf96f6bc31c0d9eddf0577f887371037 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1515/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index cafc1eb08a..2283071109 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From 9938b280eef72828a441db2afc4169f6ad21d418 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1516/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index bf9479e4eb..a2a12dc435 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 9d4886c716..84bbf3ed49 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -327,6 +327,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index b45525846d..faa583d610 100644 --- a/cache.h +++ b/cache.h @@ -560,6 +560,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index bee6054419..ae7bf6802d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2283071109..f8ec49ea9a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -295,6 +292,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 32c0b2c41e..e87f0ae8b5 100644 --- a/config.c +++ b/config.c @@ -662,6 +662,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index c79f2a9b56..e8fe2ae6b2 100644 --- a/environment.c +++ b/environment.c @@ -56,6 +56,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index d6d269f138..f7b7000702 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -544,4 +544,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 88b0bdeb33eb3ca92fd3cf967cd5bf23475141d5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1517/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index ae7bf6802d..39296a5e0c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 24e96e358b94de1cc9017b021d5312c7d76b577c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1518/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 9709d850f7843885a0824a5f0f8064c5b7f6095e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1519/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index d3acf0d213..abb75e3578 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1246,9 +1246,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2048,7 +2045,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2060,12 +2057,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2086,18 +2090,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2118,20 +2119,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From e3e2a284c2b815cd85480e5ad0e11e32eff7057f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1520/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 39296a5e0c..a1f40d2210 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f8ec49ea9a..f5f9c6cdd1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -122,14 +122,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - #define WNOHANG 1 pid_t waitpid(pid_t pid, int *status, unsigned options); @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 0093d3448e0e6a98174b6a8ac61c778ac3bb30b3 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1521/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index a1f40d2210..be78165f83 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1323,7 +1339,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From ffe777cab9c5d5466966112fa068a6e535b74a05 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1522/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index be78165f83..6f9cf6e12b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1380,6 +1433,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 6c678a7a6e0f67dba15c3a80cbe0de004deb374d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1523/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 6f9cf6e12b..ed73272937 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f5f9c6cdd1..b89711f726 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From d823962943910d00987b54c874393ef76f6db37d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1524/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index abb75e3578..ea31b47c69 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From d6b586408e82b2853ba670b007b19c4b0d1df1c8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1525/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index e82c6bfede..ca92f60b14 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9478,7 +9478,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From bd3df995a52dc40fa9ffd43b0d17919e2a72bbee Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1526/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index d44194c35f..186a232e18 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -318,4 +318,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 52ea8c8698712aa4a36de9043fdd16a83133fc07 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1527/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ed73272937..f6b29a49cb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 357177106a48bc70dc392095ffd838f77a5025a9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1528/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index f1dc5c3b6a..93b447bfe9 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -722,6 +722,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -738,6 +742,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -764,8 +772,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -780,6 +796,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -815,6 +835,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From c6a5f453a954a39a74c279d73666fe50b3f531f3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1529/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index a2a12dc435..5453d0d399 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1642,6 +1642,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From adb267b1673dc588e5a66d01eb157447f8e65d51 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1530/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index f6b29a49cb..8ff89362ae 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From e36bd2140dbdb0b3124830c061d8a3856f0b1189 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1531/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From bcfc9ba39674c6ec62e6bc5032c4f9c7de9c76cc Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1532/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From d3bc6e71de350f9dd39f54eceb99702beb5ed199 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1533/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8ff89362ae..5197ae5a7b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 50fa1769c7aec27f7981f8d8482d8a5b71a944da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1534/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 5197ae5a7b..24f9f04fb2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1767,3 +1767,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index b89711f726..e259f35f5b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -324,3 +324,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index e87f0ae8b5..fb344105af 100644 --- a/config.c +++ b/config.c @@ -878,7 +878,7 @@ int git_config(config_fn_t fn, void *data) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index f7b7000702..78c823f259 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -548,4 +548,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 8951333cb8..1722be651d 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From e0f2d8fa4041eeb7dd8e16c3c7a80278c1bbbb29 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1535/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 9dbb74344ce8badc38b8a5490000b5dbb22397c5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1536/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index df09b42840..e7f649a266 100755 --- a/git-am.sh +++ b/git-am.sh @@ -490,7 +490,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -666,7 +667,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -739,7 +741,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -763,7 +765,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From fe93d144a9a9c8cce4078bc13cdc97a2e8132d21 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1537/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 48fa516004..e0a9f675f6 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From a0927510bc91f56e2501d171a9ceec96d6357d58 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1538/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index faa583d610..c98dcea268 100644 --- a/cache.h +++ b/cache.h @@ -729,7 +729,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index 24f9f04fb2..ed03f434eb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1785,3 +1785,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index e259f35f5b..fbbb296cc4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -284,6 +284,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 78c823f259..15d32a1458 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -204,6 +204,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 1722be651d..9724e38914 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 55ecac435ca5068b2b93c5249cd19c8d7c2e1c1b Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1539/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From e5ba16a017d8c8ea9a2694997e2edfda39f29a6c Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1540/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ed03f434eb..4cacbf47d3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1788,23 +1788,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 7d51cfd9138efe5d81378e5386f15b4543d884c1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1541/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ea31b47c69..0ac2d37f22 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 0d28977e234ec25064cc021806dd4e560f9072f8 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1542/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index ca92f60b14..c5799caeca 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9478,18 +9478,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9500,6 +9489,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From f460bdf87e54b68b33e84d6534bbf6d19963612d Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1543/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4cacbf47d3..68586253df 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -638,11 +638,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 5cbe2d5fad6b1bb5b399157f0f64f90897051968 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1544/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index fbbb296cc4..9c00e75f4d 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -274,9 +274,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From d13ad3753d52c5d35df226c0d528549d5bfd21f3 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1545/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 1d95592617bd3c6d545fe5796ecb57d38f252338 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1546/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From 6dbe03f7ce5f19e1b3b288627652f6d5ab8fb741 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1547/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 5a2ce70a14455708ae569b7794ce5b3b4566e550 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1548/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e8ae1adad7..7d218e8a2d 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4006,6 +4006,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From b2ac0cceea0363e802851f04ad1ca63c76318984 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1549/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7d218e8a2d..872d24fe1d 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4021,7 +4021,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 8ce531f092a11fbe403ce69617c5271287139525 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1550/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From fd899776e9dbf18840620db94c3c9b9cc8d43b82 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1551/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index 12b964e642..1a17ac1848 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die ("Could not open '%s' for writing.", file); From 830d57af1f14ca335b1cb054f2c9bc280ddfa81a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1552/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 00f1d113cf..d7b857f8d9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From ace0f88b4adfb744d640595a91d2eae7bca29a0d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1553/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index fdf7131efd..6f765d607a 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -179,6 +180,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -189,6 +206,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -593,6 +613,9 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) continue; if (!pathspec_matches(paths, ce->name, opt->max_depth)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -1003,6 +1026,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die("no pattern given."); From 51da7a909f546cc0ae00a6259c8a3cd019e8e42a Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Mon, 27 Sep 2010 08:01:35 -0400 Subject: [PATCH 1554/3720] Side-step line-ending corruption leading to t3032 failures. By default, MSYS grep and sed throw away CR from CRLF line-endings. Tests t3032.4 through t3032.8 employ grep and fail due to this behavior. Test t3032.9 employs sed and fails. Fix by employing grep's -U/--binary and sed's -b/--binary switches to suppress the default behavior of dropping CR characters. Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t3032-merge-recursive-options.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh index 2293797553..03ea961720 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-options.sh @@ -13,9 +13,14 @@ test_description='merge-recursive options . ./test-lib.sh +if test_have_prereq MINGW; then + export GREP_OPTIONS=-U + SED_OPTIONS=-b +fi + test_expect_success 'setup' ' conflict_hunks () { - sed -n -e " + sed $SED_OPTIONS -n -e " /^<<< Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1555/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index cafc1eb08a..2283071109 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From adb8bdce7ef45b48866e16e46f9705c8f5980775 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1556/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index a8759cff80..1ec2bdacee 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index e3af9eaa87..7f80abe279 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -327,6 +327,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index d83d68c859..ade5df62f4 100644 --- a/cache.h +++ b/cache.h @@ -560,6 +560,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index bee6054419..ae7bf6802d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2283071109..f8ec49ea9a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -295,6 +292,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 625e051876..960b55c92e 100644 --- a/config.c +++ b/config.c @@ -660,6 +660,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 9564475f42..ceb14af407 100644 --- a/environment.c +++ b/environment.c @@ -56,6 +56,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index d6d269f138..f7b7000702 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -544,4 +544,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 2c44b0281be6811f5070540954ea87179d6b4aa1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1557/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index ae7bf6802d..39296a5e0c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 9f3b1ebbd682b7d60f518358a47fe761905b991f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1558/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 786e04bd8387b6a7758c30dad7f590030e2f900c Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1559/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index d3acf0d213..abb75e3578 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1246,9 +1246,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2048,7 +2045,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2060,12 +2057,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2086,18 +2090,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2118,20 +2119,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From d32ac57d53a41b2c6e05fbf64a4178fd7bfc0aa6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1560/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 39296a5e0c..a1f40d2210 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f8ec49ea9a..f5f9c6cdd1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -122,14 +122,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - #define WNOHANG 1 pid_t waitpid(pid_t pid, int *status, unsigned options); @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 3a31964ac2a759661d8783b265a5fcaa00bdcab9 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1561/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index a1f40d2210..be78165f83 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1323,7 +1339,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 13806825d19d2452aa4997c5d355101178eae4d1 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1562/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index be78165f83..6f9cf6e12b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1380,6 +1433,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 23570804110359f1d3a01a324a3beb818a4ce170 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1563/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 6f9cf6e12b..ed73272937 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f5f9c6cdd1..b89711f726 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From d8fe30124bf349b279b2ea7044b425e1527317ae Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1564/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index abb75e3578..ea31b47c69 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 5a94fdc80340624a2a7f8b1338b07eefc55e3c25 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1565/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index e82c6bfede..ca92f60b14 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9478,7 +9478,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 7cf4eb40c97986b752fa51a7ba9466f54766af1b Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1566/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index af8b9c52a9..27e74f7274 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -374,4 +374,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From fe93761f1f70307168f3a18049f46c19f7e11c23 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1567/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ed73272937..f6b29a49cb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From ba7f6cf93e7715a0980fd39fc4d224f1f5694053 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1568/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index f1dc5c3b6a..93b447bfe9 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -722,6 +722,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -738,6 +742,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -764,8 +772,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -780,6 +796,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -815,6 +835,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From b99eac90a6b67356dfc4425dffb671890ebfec23 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1569/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 1ec2bdacee..cfd8e2b84b 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1635,6 +1635,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From df20bd408d7e79ccca61b5d7c4ec519cf8547280 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1570/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index f6b29a49cb..8ff89362ae 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 0ce7ec1abaec68350182e6fd945ebf17ed451ac1 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1571/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 984163566c33de7147c223bc40736fdc4786928f Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1572/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 7037f5e854e658ab4abfdbc00bd503ecda25b763 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1573/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8ff89362ae..5197ae5a7b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 9164924e44331c89e089432222a1a1a8d1ff2376 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1574/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 5197ae5a7b..24f9f04fb2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1767,3 +1767,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index b89711f726..e259f35f5b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -324,3 +324,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 960b55c92e..9452b8bb4b 100644 --- a/config.c +++ b/config.c @@ -875,7 +875,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index f7b7000702..78c823f259 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -548,4 +548,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 8951333cb8..1722be651d 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 2f3171f7ecd64fe45d0a7a8c2312d28c2d74fa4f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1575/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From d4cd980b7559ae7444a2ad1e9595ada0be349a26 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1576/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6cdd5910db..b312da10d8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -513,7 +513,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -682,7 +683,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -755,7 +757,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -779,7 +781,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From a36c3b2eb458eaa8648a1a131b3b6a4dcd833ae2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1577/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index cb1ca973aa..2ac8cab14e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From fa0722955d5c8372a3043ee88a871e480ab56aef Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1578/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index ade5df62f4..264628c88e 100644 --- a/cache.h +++ b/cache.h @@ -729,7 +729,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index 24f9f04fb2..ed03f434eb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1785,3 +1785,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index e259f35f5b..fbbb296cc4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -284,6 +284,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 78c823f259..15d32a1458 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -204,6 +204,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 1722be651d..9724e38914 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From af670f34a78d6704eaa19019bac6c8439353227b Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1579/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 255256af1b27f8e1c9550d0a2db368d1f3859f9d Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1580/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ed03f434eb..4cacbf47d3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1788,23 +1788,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From bacbd75261067c6e0b3845cb3798d6c5484d7965 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1581/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ea31b47c69..0ac2d37f22 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 504b3c2a638f4c82e46b03b10a90c3a673e069f6 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1582/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index ca92f60b14..c5799caeca 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9478,18 +9478,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9500,6 +9489,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 93e4be88861d904900261e01c9797fbf4c3be8b4 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1583/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4cacbf47d3..68586253df 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -638,11 +638,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From d52d27e225b1c2bd8b902b4441e11f263f42ad29 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1584/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index fbbb296cc4..9c00e75f4d 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -274,9 +274,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 3d095028b88bcf8456aa31568a6152d77d36ef2a Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1585/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From f15bcee1ce9dac3f832e761a2dc9751060b2cc81 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1586/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From b3eb4db82f7522e0d871fe6678756a74f30967b7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1587/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From db32606561fe811acaa0b15d84564278cb2a735d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1588/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 47796180d2..88d4165d12 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4011,6 +4011,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 62af20ec648ed869d27b845f24465136f8a24002 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1589/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 88d4165d12..a22fe084e3 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4026,7 +4026,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 7441cb360160123753a4c84570cf33487aed7b2e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1590/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 474b58f146591052e5fba6f302d5d443c347c327 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1591/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index 12b964e642..1a17ac1848 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die ("Could not open '%s' for writing.", file); From b354289fb6b6fae0139f660154afc4fd5b0c5cd5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1592/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 00f1d113cf..d7b857f8d9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 8e7ccdb919ef1133ab4da9a10d82e75ea82b1a4e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1593/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index fdf7131efd..6f765d607a 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -179,6 +180,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -189,6 +206,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -593,6 +613,9 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) continue; if (!pathspec_matches(paths, ce->name, opt->max_depth)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -1003,6 +1026,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die("no pattern given."); From f3b86ef5dd2899867fed9192ecfe5d170b67e5ce Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Mon, 27 Sep 2010 08:01:35 -0400 Subject: [PATCH 1594/3720] Side-step line-ending corruption leading to t3032 failures. By default, MSYS grep and sed throw away CR from CRLF line-endings. Tests t3032.4 through t3032.8 employ grep and fail due to this behavior. Test t3032.9 employs sed and fails. Fix by employing grep's -U/--binary and sed's -b/--binary switches to suppress the default behavior of dropping CR characters. Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t3032-merge-recursive-options.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh index 2293797553..03ea961720 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-options.sh @@ -13,9 +13,14 @@ test_description='merge-recursive options . ./test-lib.sh +if test_have_prereq MINGW; then + export GREP_OPTIONS=-U + SED_OPTIONS=-b +fi + test_expect_success 'setup' ' conflict_hunks () { - sed -n -e " + sed $SED_OPTIONS -n -e " /^<<< Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1595/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ff35154375..01779e8d5c 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 88090de226cab15c30dfaeb6c7514a84d89fe65d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1596/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 68586253df..e4b6b6f13b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1773,7 +1773,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From 4f4ef24e34b9dab12c53e7fc5bb0321d469aa1fb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1597/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 01779e8d5c..1374bb8a27 100644 --- a/Makefile +++ b/Makefile @@ -1881,7 +1881,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1921,6 +1921,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From 8d0b3c8e06553c0d6ae9182ef3e769e21dd5877f Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1598/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index cafc1eb08a..2283071109 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From 6b8b9eb6203cbac4a1f16c5fdcc9e8186b9bc286 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1599/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index ff7c225467..7eef17ba6f 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index e3af9eaa87..7f80abe279 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -327,6 +327,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index d83d68c859..ade5df62f4 100644 --- a/cache.h +++ b/cache.h @@ -560,6 +560,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index bee6054419..ae7bf6802d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2283071109..f8ec49ea9a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -295,6 +292,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 625e051876..960b55c92e 100644 --- a/config.c +++ b/config.c @@ -660,6 +660,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 9564475f42..ceb14af407 100644 --- a/environment.c +++ b/environment.c @@ -56,6 +56,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index d6d269f138..f7b7000702 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -544,4 +544,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From bb3d2666e77e7c25717caae4775d6b920e61545f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1600/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index ae7bf6802d..39296a5e0c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 382e7d5cffb6958bff5e7cd20835ec852076e553 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1601/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 1a8b62e0caf80c67a62f401c5856f9b38e7944bb Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1602/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index d3acf0d213..abb75e3578 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1246,9 +1246,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2048,7 +2045,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2060,12 +2057,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2086,18 +2090,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2118,20 +2119,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 0b5350b99017b55dd380d4958ded14f6c0b7a8fa Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1603/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 39296a5e0c..a1f40d2210 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f8ec49ea9a..f5f9c6cdd1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -122,14 +122,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - #define WNOHANG 1 pid_t waitpid(pid_t pid, int *status, unsigned options); @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 58e62ed9f71fd9916de220189de7bea0fe5415bc Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1604/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index a1f40d2210..be78165f83 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1323,7 +1339,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 7b8f9e79a1809766e2e6566a5c487181918bc33e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1605/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index be78165f83..6f9cf6e12b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1380,6 +1433,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 5d692c9739599081178f1af2c43637847bebfb7a Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1606/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 6f9cf6e12b..ed73272937 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f5f9c6cdd1..b89711f726 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From c94b8cb76ca8a61df7d30db12e6075573373ea6f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1607/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index abb75e3578..ea31b47c69 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 781f05227e1b393c918120973d431b29c677e9cd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1608/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index e82c6bfede..ca92f60b14 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9478,7 +9478,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 3beb7f92057ca2eb8f400ea3ba0744002be3e974 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1609/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index f684993211..ba4b880c29 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -374,4 +374,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 110cde8a291defe80879081e2edbd110ccfbec32 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1610/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ed73272937..f6b29a49cb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 380609b956393d4bfc2959e959ff6ebb6fdc6f02 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1611/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index f1dc5c3b6a..93b447bfe9 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -722,6 +722,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -738,6 +742,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -764,8 +772,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -780,6 +796,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -815,6 +835,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 5a8503553c93d468cc3f72096d0cb5faf5581d16 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1612/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7eef17ba6f..850b5c9590 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1635,6 +1635,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 3a67f1bd4587a67686fc0d59540669df55fe2e20 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1613/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index f6b29a49cb..8ff89362ae 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 0b8aa0afa6a2019a1dc6a7983bfc31cae4406807 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1614/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From d551772eb7b432e191096564a27cdc128d67ff10 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1615/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From d8cb7298b32c6ecbc244ad79b944b344e25c8a7b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1616/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8ff89362ae..5197ae5a7b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From a2ec96a805975edc05d58286d3fecfe9cb0c92b8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1617/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 5197ae5a7b..24f9f04fb2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1767,3 +1767,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index b89711f726..e259f35f5b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -324,3 +324,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 960b55c92e..9452b8bb4b 100644 --- a/config.c +++ b/config.c @@ -875,7 +875,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index f7b7000702..78c823f259 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -548,4 +548,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 8951333cb8..1722be651d 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From fb6e113eefc8ca3eabc7352f787ace7416002386 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1618/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 007ba184fffbfaef0261cd573a924e9f3ce6b936 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1619/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6cdd5910db..b312da10d8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -513,7 +513,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -682,7 +683,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -755,7 +757,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -779,7 +781,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From e0e239f1d5801e6dc6aafbce2e5c8490bdc475ba Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1620/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index cb1ca973aa..2ac8cab14e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From a8522726e67460ac75cc5f9fd0809d06865af09b Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1621/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index ade5df62f4..264628c88e 100644 --- a/cache.h +++ b/cache.h @@ -729,7 +729,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index 24f9f04fb2..ed03f434eb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1785,3 +1785,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index e259f35f5b..fbbb296cc4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -284,6 +284,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 78c823f259..15d32a1458 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -204,6 +204,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 1722be651d..9724e38914 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 3ab983280ddd14afb689d099d1ea05bf7f15cdd7 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1622/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From bebf2d63483d566e04422b7e0c0194d86719f755 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1623/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ed03f434eb..4cacbf47d3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1788,23 +1788,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 9a95db9a2619a909a0bb650429fc2639a6a2c65c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1624/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ea31b47c69..0ac2d37f22 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 550f380bcccbc62d41ebe224f1fe4417a3e2a191 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1625/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index ca92f60b14..c5799caeca 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9478,18 +9478,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9500,6 +9489,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 9123a3d382eb6b3e8b8019ced340a273bb0221c2 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1626/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4cacbf47d3..68586253df 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -638,11 +638,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 2902197ece30d07aa0015e053b3893974554cc9e Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1627/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index fbbb296cc4..9c00e75f4d 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -274,9 +274,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 31bef7b47c17617d05359051d9d69c4a250b7c8b Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1628/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From cb1c032ec453799be5ed0ea6b98d4cae3f6dd684 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1629/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From ae8555be213b2a446401deaec98764d97a4a81d2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1630/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From db7630033b04ba997fcee913485a00f77b390871 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1631/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 1025c2f716..7f7b071e34 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4016,6 +4016,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 4ab8b0855655bd4a3a50bf258aeb959b37abf7dd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1632/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7f7b071e34..65a060ac3b 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4031,7 +4031,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 5962cee42ebb54b428113e497078729f0151c2e2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1633/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 2edbd27a7e19c27fbbef69611d8fc867f4c57b39 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1634/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index 12b964e642..1a17ac1848 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die ("Could not open '%s' for writing.", file); From 06a850bb26b96cfd71fb727188994b58e6decb04 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1635/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 00f1d113cf..d7b857f8d9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From e232abe04718c8137016ce025f4ac315c244cf87 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1636/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index fdf7131efd..6f765d607a 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -179,6 +180,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -189,6 +206,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -593,6 +613,9 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) continue; if (!pathspec_matches(paths, ce->name, opt->max_depth)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -1003,6 +1026,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die("no pattern given."); From 81a0f841e67fe01c8b93d1942435425f96073c0e Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Mon, 27 Sep 2010 08:01:35 -0400 Subject: [PATCH 1637/3720] Side-step line-ending corruption leading to t3032 failures. By default, MSYS grep and sed throw away CR from CRLF line-endings. Tests t3032.4 through t3032.8 employ grep and fail due to this behavior. Test t3032.9 employs sed and fails. Fix by employing grep's -U/--binary and sed's -b/--binary switches to suppress the default behavior of dropping CR characters. Signed-off-by: Eric Sunshine Signed-off-by: Pat Thoyts --- t/t3032-merge-recursive-options.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh index adc72840d1..c96599a6bb 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-options.sh @@ -13,9 +13,14 @@ test_description='merge-recursive options . ./test-lib.sh +if test_have_prereq MINGW; then + export GREP_OPTIONS=-U + SED_OPTIONS=-b +fi + test_expect_success 'setup' ' conflict_hunks () { - sed -n -e " + sed $SED_OPTIONS -n -e " /^<<< Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1638/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ade79232f4..d5a67935bc 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 5ed5897fadeff1498c99142a87d8fd441f078bf7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1639/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 68586253df..e4b6b6f13b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1773,7 +1773,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From 83ae555dc46c6632df1f5dffa3820d7281e79b77 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1640/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d5a67935bc..0f340fea1c 100644 --- a/Makefile +++ b/Makefile @@ -1883,7 +1883,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1923,6 +1923,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From 5cf480322eee233abce5870d5f381509535fe7c7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1641/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index f072a8ed48..fbae0834e6 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -340,6 +340,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From fd6937e0e6ccb78eb4347c427248e25c2d6739c8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:06:48 +0100 Subject: [PATCH 1642/3720] Handle new t1510 test cases properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1510-repo-setup.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh index c3798ce179..86785147c4 100755 --- a/t/t1510-repo-setup.sh +++ b/t/t1510-repo-setup.sh @@ -39,6 +39,10 @@ test_description='Tests of cwd/prefix/worktree/gitdir setup in all cases' # prefix is NULL. # +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_repo() { ( cd "$1" && From 63d9aad326986f3c89285282ff7daf0c9bfa8c96 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 13 Jan 2011 11:56:16 -0800 Subject: [PATCH 1643/3720] Fix mismerge at 37ef456 Two tests have been lost and I do not know why... Signed-off-by: Junio C Hamano --- t/t3032-merge-recursive-options.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh index 44f5421be4..2b17311cb0 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-options.sh @@ -110,6 +110,20 @@ test_expect_success '--ignore-space-change makes merge succeed' ' git merge-recursive --ignore-space-change HEAD^ -- HEAD remote ' +test_expect_success 'naive cherry-pick fails' ' + git read-tree --reset -u HEAD && + test_must_fail git cherry-pick --no-commit remote && + git read-tree --reset -u HEAD && + test_must_fail git cherry-pick remote && + test_must_fail git update-index --refresh && + grep "<<<<<<" text.txt +' + +test_expect_success '-Xignore-space-change makes cherry-pick succeed' ' + git read-tree --reset -u HEAD && + git cherry-pick --no-commit -Xignore-space-change remote +' + test_expect_success '--ignore-space-change: our w/s-only change wins' ' q_to_cr <<-\EOF >expected && justice and holiness and is the nurse of his age and theQ From 938e29690544ff4fe72771e7a4b5d91a81c71c30 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1644/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index cafc1eb08a..2283071109 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From bebf11ed648fa7c7db6d2aa03eb119847f244ece Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1645/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c5e183516a..724d79b8d5 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index e3af9eaa87..7f80abe279 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -327,6 +327,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 4beb2dc6ff..5483b54d7a 100644 --- a/cache.h +++ b/cache.h @@ -575,6 +575,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index bee6054419..ae7bf6802d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,6 +172,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -160,17 +206,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2283071109..f8ec49ea9a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -295,6 +292,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 625e051876..960b55c92e 100644 --- a/config.c +++ b/config.c @@ -660,6 +660,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 9564475f42..ceb14af407 100644 --- a/environment.c +++ b/environment.c @@ -56,6 +56,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index d6d269f138..f7b7000702 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -544,4 +544,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 9051af7d192f290594afc5b251d52263117ca5f4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1646/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index ae7bf6802d..39296a5e0c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 43a21dc3994603f9ed199603e20efb7c0c613730 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1647/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 209786a97e93105a90355063245f3c086ea969ca Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1648/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index d3acf0d213..abb75e3578 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1246,9 +1246,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2048,7 +2045,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2060,12 +2057,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2086,18 +2090,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2118,20 +2119,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 202abfa0decf9926a4460b7465153ffd08fb96f2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 1649/3720] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 39296a5e0c..a1f40d2210 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f8ec49ea9a..f5f9c6cdd1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -122,14 +122,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - #define WNOHANG 1 pid_t waitpid(pid_t pid, int *status, unsigned options); @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From afbf7b686650e73713747ac0f236ae00c01ab9ed Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 1650/3720] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index a1f40d2210..be78165f83 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1323,7 +1339,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 74510dc3ba48a4e26836c74711dd9306a113f0dd Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 1651/3720] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index be78165f83..6f9cf6e12b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1380,6 +1433,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 08e6f921a09466f30938cdd7907d9c4d9c36cf63 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 1652/3720] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 6f9cf6e12b..ed73272937 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f5f9c6cdd1..b89711f726 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 8ea6546f426d4b0390df70553b0246c818da6962 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1653/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index abb75e3578..ea31b47c69 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 1f55fc30af327168b66ad642447b394e9d7ddef5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1654/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index e82c6bfede..ca92f60b14 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9478,7 +9478,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From da59f95559653e63f47e94448bef80c2cf204534 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1655/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index f684993211..ba4b880c29 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -374,4 +374,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 14b3709e0e437d58faf198fae529d6e5e4e20ddf Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1656/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ed73272937..f6b29a49cb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 047ce2e03af6e57cf61cc580d21805424b901aa4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1657/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index f1dc5c3b6a..93b447bfe9 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -722,6 +722,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -738,6 +742,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -764,8 +772,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -780,6 +796,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -815,6 +835,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 8d66417de3ae5081a51e54213f65b443f0b1fd9d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1658/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 724d79b8d5..3157340f3d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1644,6 +1644,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 4d27bc5642d2304b5d364d3c76f803ffb6a92739 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 1659/3720] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index f6b29a49cb..8ff89362ae 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) { From 88662a72d956fb894d95931edae711b2d32306f4 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1660/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 8999f35036e3acd43838daba10effa4cdeb8d599 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1661/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 1a525079e7ec61c7387cde0aadd302e47e1856ad Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 May 2010 12:42:50 +0200 Subject: [PATCH 1662/3720] mingw_rmdir: set errno=ENOTEMPTY when appropriate On Windows, EACCES overrules ENOTEMPTY when calling rmdir(). But if the directory is busy, we only want to retry deleting the directory if it is empty, so test specifically for that case and set ENOTEMPTY rather than EACCES. Noticed by Greg Hazel. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8ff89362ae..5197ae5a7b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -233,14 +233,42 @@ int mingw_unlink(const char *pathname) return ret; } +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + #undef rmdir int mingw_rmdir(const char *pathname) { - int ret, tries = 0; + int ret, tries = 0; while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (errno != EACCES) break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } /* * We assume that some other process had the source or * destination file open at the wrong moment and retry. From 1927dd072ec4ba833cb038a4e5c19a70d8b787f5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1663/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a7..5efd44a8ea 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 5197ae5a7b..24f9f04fb2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1767,3 +1767,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index b89711f726..e259f35f5b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -324,3 +324,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 960b55c92e..9452b8bb4b 100644 --- a/config.c +++ b/config.c @@ -875,7 +875,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index f7b7000702..78c823f259 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -548,4 +548,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 8951333cb8..1722be651d 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From ca245cb3b6280efdc1c2227cab42e1d33b0d040c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1664/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From b40c5f2a8753ada954bd45386d6812c8f147af88 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1665/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6cdd5910db..b312da10d8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -513,7 +513,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -682,7 +683,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -755,7 +757,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -779,7 +781,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 02d77ad10e7b5bb74e3cfa9895d107537cd65afc Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1666/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 0fdc541a7c..6f08071f90 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From d0e09dadb8b668ac79c120e0f77438569bce2ac4 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1667/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 5483b54d7a..c4f629f027 100644 --- a/cache.h +++ b/cache.h @@ -744,7 +744,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index 24f9f04fb2..ed03f434eb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1785,3 +1785,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index e259f35f5b..fbbb296cc4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -284,6 +284,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 78c823f259..15d32a1458 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -204,6 +204,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 1722be651d..9724e38914 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 53d2cd68879842f5f5c3730c5a51dd8c3c7652aa Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1668/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5efd44a8ea..432c6e4261 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From e4f48abd35a17c1106b2f7113a32e42b4b6b651d Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1669/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ed03f434eb..4cacbf47d3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1788,23 +1788,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 886201f06b9ad9ce45dc81f932a09a5219d05ec6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1670/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ea31b47c69..0ac2d37f22 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 1e1f5afb8a55361b2cbdc75618e87a93225b8a17 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1671/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index ca92f60b14..c5799caeca 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9478,18 +9478,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9500,6 +9489,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 8b72752d8272624e3da5598c130ee0963e004c00 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1672/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4cacbf47d3..68586253df 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -638,11 +638,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From f5fc641efb45fb4866dc5db74d2296c3b1a44d9e Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1673/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index fbbb296cc4..9c00e75f4d 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -274,9 +274,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 72c244d917f615add64afaf7ccaea7cbf31c6d53 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1674/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 551bf166ccf090cbb16c3cc93df27281ecf18a55 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1675/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From e68451c74f8a9d3fd6fca863b9a8ef4d554d6732 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1676/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From b37cf3eff093f6f21ddd0fcfdecf13762c5174f1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1677/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0779f12d61..5cd07a9fe3 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4016,6 +4016,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From cb867a89216f47a8e828ca3c7617831f1648aeb2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1678/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 5cd07a9fe3..16e4857496 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4031,7 +4031,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From b1f7f84484eb31664fc43ac4c04b2099bfb1e8b1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1679/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From f653694a30848355eb3f11aedc9e39f596c1ad64 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1680/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index 5f817ad77f..2f1d57a787 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die ("Could not open '%s' for writing.", file); From 3c1ac8c41beba83fa5fd6cd9a21ac0d04772252b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1681/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 00f1d113cf..d7b857f8d9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 4e41bf306e369e6c3ccf061305abf977225106f7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1682/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index c3af8760cc..6dbae9e944 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -179,6 +180,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -189,6 +206,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -493,6 +513,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -902,6 +925,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die("no pattern given."); From 39165461cf8c1f7e8a057cc73229cbdfc20e149d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1683/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ade79232f4..d5a67935bc 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From fae4bbdb5ee855547f447b4a3279f070728acc9f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1684/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 68586253df..e4b6b6f13b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1773,7 +1773,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From 39514987f3e430be8ef91757ce4bc653bfd455e8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1685/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d5a67935bc..0f340fea1c 100644 --- a/Makefile +++ b/Makefile @@ -1883,7 +1883,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1923,6 +1923,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From 5d2f323e8d9525fe03c82b2063baa266fd8be5b6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1686/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index da6252b117..4b7236abcf 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -340,6 +340,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From 4aed09a4fd89e5b74c8fd757a83a81a7c4636899 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 2 Feb 2011 15:48:06 +0000 Subject: [PATCH 1687/3720] t3509: use unconstrained initial test to setup repository. The first test did not run on msysGit due to the SYMLINKS constraint and so subsequent tests failed because the test repository was not initialized. Signed-off-by: Pat Thoyts --- t/t3509-cherry-pick-merge-df.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh index 948ca1bce6..df921d1f33 100755 --- a/t/t3509-cherry-pick-merge-df.sh +++ b/t/t3509-cherry-pick-merge-df.sh @@ -3,12 +3,14 @@ test_description='Test cherry-pick with directory/file conflicts' . ./test-lib.sh -test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' ' +test_expect_success 'Initialize repository' ' mkdir a && >a/f && git add a && - git commit -m a && + git commit -m a +' +test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' ' mkdir b && ln -s ../a b/a && git add b && From 14d0be95c49dfb990a2962d966851bf5513cbdc4 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Feb 2011 23:40:22 +0100 Subject: [PATCH 1688/3720] t4120-apply-popt: help systems with core.filemode=false A test case verifies that filemode-only patches work as expected. Help systems where "test -x" does not work by applying the test patch also to the index, where the effects can be verified even on such systems. Signed-off-by: Johannes Sixt Signed-off-by: Pat Thoyts --- t/t4120-apply-popt.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh index 579c9e6105..a33d510bf6 100755 --- a/t/t4120-apply-popt.sh +++ b/t/t4120-apply-popt.sh @@ -6,6 +6,7 @@ test_description='git apply -p handling.' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh test_expect_success setup ' mkdir sub && @@ -62,8 +63,12 @@ test_expect_success 'apply (-p2) diff, mode change only' ' old mode 100644 new mode 100755 EOF - chmod 644 file1 && - git apply -p2 patch.chmod && + test_chmod -x file1 && + git apply --index -p2 patch.chmod && + case $(git ls-files -s file1) in 100755*) : good;; *) false;; esac +' + +test_expect_success FILEMODE 'file mode was changed' ' test -x file1 ' From b7f67992f24217ce46bb4194f6ee5b72a96679dc Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 3 Feb 2011 12:33:35 +0000 Subject: [PATCH 1689/3720] t7407: fix line endings for mingw build Signed-off-by: Pat Thoyts --- t/t7407-submodule-foreach.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 1d67ef549e..4c847645db 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -254,6 +254,10 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached ) && git submodule status --cached --recursive -- nested1 > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' From 844cb2210d9fc66627c562b7a2fdaf6b9cd52ae1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 4 Feb 2011 09:41:58 +0100 Subject: [PATCH 1690/3720] start_command: flush buffers in the WIN32 code path as well The POSIX code path did The Right Thing already, but we have to do the same on Windows. This bug caused failures in t5526-fetch-submodules, where the output of 'git fetch --recurse-submodules' was in the wrong order. Debugged-by: Johannes Schindelin Signed-off-by: Johannes Sixt Signed-off-by: Pat Thoyts --- run-command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run-command.c b/run-command.c index 2a1041ef65..f91e446c86 100644 --- a/run-command.c +++ b/run-command.c @@ -194,6 +194,7 @@ fail_pipe: } trace_argv_printf(cmd->argv, "trace: run_command:"); + fflush(NULL); #ifndef WIN32 { @@ -201,7 +202,6 @@ fail_pipe: if (pipe(notify_pipe)) notify_pipe[0] = notify_pipe[1] = -1; - fflush(NULL); cmd->pid = fork(); if (!cmd->pid) { /* From 63da89138b35a54c72deb2f3a01d52cd1bd5d740 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 1691/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 6dbae9e944..bde91667e0 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -997,6 +997,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From ce3fbf2cc6a66fb0f99b6d43e2988910105c189f Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1692/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index fe6ba34043..8b159c4447 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From 063d073dc9a935bd22a90761e1f0bec002b30923 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1693/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c5e183516a..724d79b8d5 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 4f5348eec6..87aa7a909a 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -327,6 +327,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index c2d59d31ff..6aa15e0151 100644 --- a/cache.h +++ b/cache.h @@ -575,6 +575,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 878b1de97c..92d4777f81 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 8b159c4447..b89711f726 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -293,6 +290,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 625e051876..960b55c92e 100644 --- a/config.c +++ b/config.c @@ -660,6 +660,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 9564475f42..ceb14af407 100644 --- a/environment.c +++ b/environment.c @@ -56,6 +56,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 9c23622ed5..ae556d0a65 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -550,4 +550,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 9c5da3e257748c5c9c6c293445aa185505fe2a82 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1694/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 92d4777f81..a9564ee332 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 2e9c3a793f5218a967cd25670007d1f097b621be Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1695/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From aa8d43d9403266c944c98420e20054456cc495bc Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1696/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index d3acf0d213..abb75e3578 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1246,9 +1246,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2048,7 +2045,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2060,12 +2057,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2086,18 +2090,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2118,20 +2119,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 2eeeab047c85956764f2d30fbe6f5e0a84befcb8 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1697/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index abb75e3578..ea31b47c69 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 82f3e26e7b70d0eea82fd997b3d732c82e38de6c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1698/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index e82c6bfede..ca92f60b14 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9478,7 +9478,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 6e7dec743fa8e262079f09c04fd25b9d3b1d24b4 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1699/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index f684993211..ba4b880c29 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -374,4 +374,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 6552981470dca4beff070c4b852f6d4ba4ce4c3e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1700/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index f1dc5c3b6a..93b447bfe9 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -722,6 +722,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -738,6 +742,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -764,8 +772,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -780,6 +796,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -815,6 +835,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 70d39fd196deb3bd5c887771082aa725c7e722f9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1701/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 724d79b8d5..3157340f3d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1644,6 +1644,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..00f1d113cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 5af782af08075f08f87052a708969772628a7555 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1702/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 9fcaa7317bdd5ebd4d62cd7a6f30e3c1d3314883 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1703/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From c5843bec6268cd725c706f1776facd97f4634c1d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1704/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index dad86fecfe..57d74cb37f 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -159,7 +159,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (git_config_global() && home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index a9564ee332..cb902a342c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1797,3 +1797,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index b89711f726..e259f35f5b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -324,3 +324,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 960b55c92e..9452b8bb4b 100644 --- a/config.c +++ b/config.c @@ -875,7 +875,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index ae556d0a65..a4087b4273 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -554,4 +554,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 8951333cb8..1722be651d 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 32645a35972485dfb14dee2f0e36e71e09f7f626 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1705/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 6c7de834d959991c69967241459f193f5a5e8e43 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1706/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6cdd5910db..b312da10d8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -513,7 +513,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -682,7 +683,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -755,7 +757,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -779,7 +781,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From dd7c81eb195fb64d57ec85badcf41d3f64366eb0 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1707/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 0fdc541a7c..6f08071f90 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 554d4ed7f8d84422be71fd7c487f25f3ab3b3c03 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1708/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 6aa15e0151..d094aeb145 100644 --- a/cache.h +++ b/cache.h @@ -746,7 +746,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index cb902a342c..67a7a1d8e6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1815,3 +1815,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index e259f35f5b..fbbb296cc4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -284,6 +284,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index a4087b4273..2ca2fad70e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -210,6 +210,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 1722be651d..9724e38914 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From f16d6a64489a36ea23a937a8c38a391e7d2ac2b8 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1709/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 57d74cb37f..84a1721699 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -348,7 +348,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From c9736e4e6084dd189f55b42bd4221f86a33c4871 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1710/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 67a7a1d8e6..48a3b760d9 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1818,23 +1818,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 53ed2ca0075a7a46ddf5dab6a871af17857aa8f5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1711/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ea31b47c69..0ac2d37f22 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 5905c9c5dcba86d482b69886fc576afec359d9e5 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1712/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index ca92f60b14..c5799caeca 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9478,18 +9478,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9500,6 +9489,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From e7cae66140fe451f9e488aa1c4d9a8be99dd1cec Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1713/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 48a3b760d9..318c6560ec 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -668,11 +668,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From ef83386efa6eb1d757a811a79dfc9de2be53a59e Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1714/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index fbbb296cc4..9c00e75f4d 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -274,9 +274,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From c3c6c730b59f31767856b17d37a587df2411150c Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1715/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 2955cb99bc30fbaeb1f2da824a13917d22f1537f Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1716/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From a30ae657237d53e1e925db29ffc9b1dfa6fa03c6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1717/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index b46ed3baef..8a60b32d66 100644 --- a/log-tree.c +++ b/log-tree.c @@ -526,7 +526,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From b7c571b37445b9446c40f0d7f7e7eaa332b4aab7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1718/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0779f12d61..5cd07a9fe3 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4016,6 +4016,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 1092ccab2e45ea78fb56f973122a5fcd252f3ef3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1719/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 5cd07a9fe3..16e4857496 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4031,7 +4031,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 3428898e03b560d81d073f4f0f16c39a79175088 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1720/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 9d59d6c4ac3bc0d6a85ad474e1012b8111213a23 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1721/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index f8e51f9b03..4be621c7f2 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die ("Could not open '%s' for writing.", file); From 78aa4ec6152cefc19d9153c8665fc65c3a3bfa85 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1722/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 00f1d113cf..d7b857f8d9 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 763307e8c33a55094cd84d836ded55bb2dfd07e7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1723/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index c3af8760cc..6dbae9e944 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -179,6 +180,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -189,6 +206,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -493,6 +513,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -902,6 +925,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die("no pattern given."); From 02d70fd2c80f492911b1b94681a218b1588c7c87 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1724/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ade79232f4..d5a67935bc 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From ab6946f825d2250e37fd2a49e791d97689659701 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1725/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 318c6560ec..6750e672f4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1803,7 +1803,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From 92b746a08090baea07b3d410638322afb89494af Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1726/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d5a67935bc..0f340fea1c 100644 --- a/Makefile +++ b/Makefile @@ -1883,7 +1883,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1923,6 +1923,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From ad4b164a72c770757b6ace9449de4648ee7a508d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1727/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index da6252b117..4b7236abcf 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -340,6 +340,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From a42a2cd1b3399beb6b7fe1bc633ce1599021bbbb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 1728/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index bde91667e0..d39e0cde57 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -997,7 +997,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From e91fdbabfe29b6e37f1bc582316a82f7784a0275 Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 1729/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From 3377895dc414f7c659da304ea17d252d22b630e6 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1730/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6750e672f4..d52756254a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From ad4cb95da413f5214ce98a333a3b3b93009e5945 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 12:39:31 +0100 Subject: [PATCH 1731/3720] Remove unused variables Noticed by gcc 4.6.0. Signed-off-by: Johannes Schindelin --- builtin/fsck.c | 3 +-- builtin/remote-ext.c | 4 ---- diff.c | 3 +-- merge-recursive.c | 4 ---- reachable.c | 5 ----- test-subprocess.c | 3 +-- transport-helper.c | 3 +-- 7 files changed, 4 insertions(+), 21 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index 795aba087f..5ae0366bc8 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -140,11 +140,10 @@ static int traverse_reachable(void) int result = 0; while (pending.nr) { struct object_array_entry *entry; - struct object *obj, *parent; + struct object *obj; entry = pending.objects + --pending.nr; obj = entry->item; - parent = (struct object *) entry->name; result |= traverse_one_object(obj); } return !!result; diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index ea71977c83..2343030b14 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -30,16 +30,12 @@ static char *strip_escapes(const char *str, const char *service, size_t rpos = 0; int escape = 0; char special = 0; - size_t pslen = 0; - size_t pSlen = 0; size_t psoff = 0; struct strbuf ret = STRBUF_INIT; /* Calculate prefix length for \s and lengths for \s and \S */ if (!strncmp(service, "git-", 4)) psoff = 4; - pSlen = strlen(service); - pslen = pSlen - psoff; /* Pass the service to command. */ setenv("GIT_EXT_SERVICE", service, 1); diff --git a/diff.c b/diff.c index 5422c43882..4c1778b172 100644 --- a/diff.c +++ b/diff.c @@ -1235,7 +1235,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; int width, name_width; - const char *reset, *set, *add_c, *del_c; + const char *reset, *add_c, *del_c; const char *line_prefix = ""; struct strbuf *msg = NULL; @@ -1262,7 +1262,6 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) /* Find the longest filename and max number of changes */ reset = diff_get_color_opt(options, DIFF_RESET); - set = diff_get_color_opt(options, DIFF_PLAIN); add_c = diff_get_color_opt(options, DIFF_FILE_NEW); del_c = diff_get_color_opt(options, DIFF_FILE_OLD); diff --git a/merge-recursive.c b/merge-recursive.c index 16c2dbeab9..b7369a2466 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -366,7 +366,6 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o, */ const char *last_file = NULL; int last_len = 0; - struct stage_data *last_e; int i; for (i = 0; i < entries->nr; i++) { @@ -396,7 +395,6 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o, if (S_ISREG(e->stages[2].mode) || S_ISLNK(e->stages[2].mode)) { last_file = path; last_len = len; - last_e = e; } else { last_file = NULL; } @@ -971,7 +969,6 @@ static int process_renames(struct merge_options *o, } for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) { - char *src; struct string_list *renames1, *renames2Dst; struct rename *ren1 = NULL, *ren2 = NULL; const char *branch1, *branch2; @@ -1006,7 +1003,6 @@ static int process_renames(struct merge_options *o, ren2 = ren1; ren1 = tmp; } - src = ren1->pair->one->path; ren1->dst_entry->processed = 1; ren1->src_entry->processed = 1; diff --git a/reachable.c b/reachable.c index a03fabf060..3fc6b1d320 100644 --- a/reachable.c +++ b/reachable.c @@ -70,16 +70,11 @@ static void process_tree(struct tree *tree, static void process_tag(struct tag *tag, struct object_array *p, const char *name) { struct object *obj = &tag->object; - struct name_path me; if (obj->flags & SEEN) return; obj->flags |= SEEN; - me.up = NULL; - me.elem = "tag:/"; - me.elem_len = 5; - if (parse_tag(tag) < 0) die("bad tag object %s", sha1_to_hex(obj->sha1)); if (tag->tagged) diff --git a/test-subprocess.c b/test-subprocess.c index 667d3e5079..8926bc52a9 100644 --- a/test-subprocess.c +++ b/test-subprocess.c @@ -3,11 +3,10 @@ int main(int argc, char **argv) { - const char *prefix; struct child_process cp; int nogit = 0; - prefix = setup_git_directory_gently(&nogit); + setup_git_directory_gently(&nogit); if (nogit) die("No git repo found"); if (!strcmp(argv[1], "--setup-work-tree")) { diff --git a/transport-helper.c b/transport-helper.c index 4e4754c32b..f3b637a27f 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -562,10 +562,9 @@ static int push_refs_with_push(struct transport *transport, int mirror = flags & TRANSPORT_PUSH_MIRROR; struct helper_data *data = transport->data; struct strbuf buf = STRBUF_INIT; - struct child_process *helper; struct ref *ref; - helper = get_helper(transport); + get_helper(transport); if (!data->push) return 1; From 7f37564bb4a8441c9779355f3809cf6b15ebf0b1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 12:40:09 +0100 Subject: [PATCH 1732/3720] Actually use retval This is most likely a bug. Nocited by gcc 4.6.0. Signed-off-by: Johannes Schindelin --- tree-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree-diff.c b/tree-diff.c index 3954281f50..9e2dc7056f 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -58,7 +58,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } strbuf_setlen(base, old_baselen); - return 0; + return retval; } /* A whole sub-tree went away or appeared */ From 96ab8ba012cb896172f5d516ec3bb719c4ce6efe Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1733/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 62eccd3391..8d768ce3d6 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From dbf24ff40b8ff7d201ef753f4928248f0923a928 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1734/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 8e4d584390..84b0b35fd5 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 8f5cfd7122..2094ec1aaa 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -327,6 +327,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index f765cf5da2..d4b9baa399 100644 --- a/cache.h +++ b/cache.h @@ -576,6 +576,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 878b1de97c..92d4777f81 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 8d768ce3d6..06f4d3e0cc 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -309,6 +306,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 763ddce9e9..7b3a14812b 100644 --- a/config.c +++ b/config.c @@ -660,6 +660,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index f4549d3f7b..6984119d01 100644 --- a/environment.c +++ b/environment.c @@ -56,6 +56,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 49b50eec86..25963ec7bd 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -566,4 +566,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From dc74f4881259a69b568f90c627efb6819b6460a0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1735/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 92d4777f81..a9564ee332 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 087379c88f71e91446562e11c6d482055a15fa6d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1736/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 34761a838201d7840b47501701718fe47d49643e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1737/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index d3acf0d213..abb75e3578 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1246,9 +1246,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2048,7 +2045,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2060,12 +2057,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2086,18 +2090,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2118,20 +2119,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 344edffdaaa7dab1fa8a3f08647767a3c8517b48 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1738/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index abb75e3578..ea31b47c69 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 309eaa83df96172c694bd935d6ecca48f6092509 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1739/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index e82c6bfede..ca92f60b14 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9478,7 +9478,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From c8b11574c2b4739a9c6f70d6dff2cf9db029b267 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1740/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index ce4ba1379e..204a6bf1b2 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -371,4 +371,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From dbfab0cb5876dbf52eebf403bdc5054599bb912b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1741/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index f1dc5c3b6a..93b447bfe9 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -722,6 +722,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -738,6 +742,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -764,8 +772,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -780,6 +796,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -815,6 +835,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 912a1943a9ceaf8c3b605054af434fb970a36e95 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1742/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 84b0b35fd5..a13db38a92 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1642,6 +1642,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 27050e7c16..21e84f1838 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 0aefc9d2e5cbc37c6d3d7227fb748ecf30668e63 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1743/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 640d1d3b096867ee55278997080151894b53c5d8 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1744/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 3213319f1df318128b8a6e62f6135fa11af11297 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1745/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 3e3c528497..5ae76049f7 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index a9564ee332..cb902a342c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1797,3 +1797,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index 06f4d3e0cc..1f754aed3b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -340,3 +340,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 7b3a14812b..d7e2eaebd8 100644 --- a/config.c +++ b/config.c @@ -872,7 +872,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 25963ec7bd..a69b634c16 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -570,4 +570,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 4d73cc9cd2..39b576c298 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 28987494bcba1986cffbef44e4f027b7d65b528e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1746/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 49211797410a16c7291f02ab73004b800513acfd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1747/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6cdd5910db..b312da10d8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -513,7 +513,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -682,7 +683,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -755,7 +757,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -779,7 +781,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From d20b1a1ea9fd29c75d129073401f95671c34449a Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1748/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 7cc9a52cbf..f6ffb1576d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From b2022528ff7ddbcd85aa4e7b1f6e10622b3f9eef Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1749/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index d4b9baa399..da4f2b117d 100644 --- a/cache.h +++ b/cache.h @@ -747,7 +747,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index cb902a342c..67a7a1d8e6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1815,3 +1815,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 1f754aed3b..a37b2718d5 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -300,6 +300,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index a69b634c16..d04ed16a93 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -210,6 +210,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 39b576c298..8745aad206 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From c3eedbe4bc51b9d8d2cdb3468475fe90a06dd59b Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1750/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5ae76049f7..9bf63d8c8a 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 4c97457b733cb3e6d29ef9a49cfbbc3c33cbd088 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1751/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 67a7a1d8e6..48a3b760d9 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1818,23 +1818,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 6f46b25caa9f726f9603411a4043f6ff91d9fbec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1752/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ea31b47c69..0ac2d37f22 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1154,6 +1154,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 233a21370375c4241572e4114f4b9810f1eac1f8 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1753/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index ca92f60b14..c5799caeca 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9478,18 +9478,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9500,6 +9489,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 8e5cfdfe26fc72c5aa211645d9143029feef8341 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1754/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 48a3b760d9..318c6560ec 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -668,11 +668,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 7129b4c90e368076febe496f858e5e5cd687c115 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1755/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index a37b2718d5..9155ce3af2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 748a7f1181ac6d644838d086ba687b8f7bff58a1 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1756/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From f74189daffc1c66d4fdf4ffec1d705d2393306a8 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1757/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From e87aa9facc5896386437b9e0a68de62c60f98269 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1758/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index 2a1e3a94c9..59133640f4 100644 --- a/log-tree.c +++ b/log-tree.c @@ -506,7 +506,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 7d7ed86182f76b371ae5ebd5319f105497fda71d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1759/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9dccfb01d6..250fb65d9c 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4016,6 +4016,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 33fd7256e26d058d8946e96cbbe35aa1390de2b8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1760/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 250fb65d9c..cf505828fe 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4031,7 +4031,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From ebd973813c426ae6ea3697d1594869b5ac5de678 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1761/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From facf6228e1c2d016e71df4a0803fde4dc6c829b0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1762/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index e127d5a68b..90fb38d353 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -278,6 +278,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die ("Could not open '%s' for writing.", file); From c1bec67f00c989d9fd295aa01d9cc8533afb1d1e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1763/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 21e84f1838..36f0da37f7 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From fb47a12ca70394ce337c074c27835ba83a6bf24d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1764/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 0bf8c0116a..a32edc1428 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -178,6 +179,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -188,6 +205,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -492,6 +512,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -907,6 +930,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die("no pattern given."); From 40795dc6f132c77e3f423fc2792ccb63aad1ca4d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1765/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9cd0dbf4d4..6ef96eea68 100644 --- a/Makefile +++ b/Makefile @@ -267,7 +267,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 263511e6db32b316d4855d0b88037dfacd69f40a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1766/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 318c6560ec..6750e672f4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1803,7 +1803,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From 448087d3bf3a1fb9b856da2f1430913d75b1a42b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1767/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6ef96eea68..14e4013fb7 100644 --- a/Makefile +++ b/Makefile @@ -1898,7 +1898,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1938,6 +1938,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From afee5dfdfad5a7e1d676a75bb44697dfa47e4beb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1768/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index da6252b117..4b7236abcf 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -340,6 +340,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From 3e3f8defdf9e67999566ad9ed639af871894d5aa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 1769/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index a32edc1428..036397a4bf 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1002,6 +1002,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From a6f7d64f3fdf576dd41af99014620428f0c7e8cf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 1770/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index 036397a4bf..e675009fa8 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1002,7 +1002,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From 1fb56b497721a4be371274647800c60885df39a9 Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 1771/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From 2ec449c2ca6a787d7d8a7beb51dba656f02291be Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1772/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6750e672f4..d52756254a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 44123e8405944b0c22065a3258cec2f73693f019 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 12:39:31 +0100 Subject: [PATCH 1773/3720] Remove unused variables Noticed by gcc 4.6.0. Signed-off-by: Johannes Schindelin --- builtin/fsck.c | 3 +-- builtin/remote-ext.c | 4 ---- diff.c | 3 +-- merge-recursive.c | 4 ---- reachable.c | 5 ----- test-subprocess.c | 3 +-- transport-helper.c | 3 +-- 7 files changed, 4 insertions(+), 21 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index 795aba087f..5ae0366bc8 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -140,11 +140,10 @@ static int traverse_reachable(void) int result = 0; while (pending.nr) { struct object_array_entry *entry; - struct object *obj, *parent; + struct object *obj; entry = pending.objects + --pending.nr; obj = entry->item; - parent = (struct object *) entry->name; result |= traverse_one_object(obj); } return !!result; diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index ea71977c83..2343030b14 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -30,16 +30,12 @@ static char *strip_escapes(const char *str, const char *service, size_t rpos = 0; int escape = 0; char special = 0; - size_t pslen = 0; - size_t pSlen = 0; size_t psoff = 0; struct strbuf ret = STRBUF_INIT; /* Calculate prefix length for \s and lengths for \s and \S */ if (!strncmp(service, "git-", 4)) psoff = 4; - pSlen = strlen(service); - pslen = pSlen - psoff; /* Pass the service to command. */ setenv("GIT_EXT_SERVICE", service, 1); diff --git a/diff.c b/diff.c index 42a107c58a..18f8e997fd 100644 --- a/diff.c +++ b/diff.c @@ -1242,7 +1242,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; int width, name_width; - const char *reset, *set, *add_c, *del_c; + const char *reset, *add_c, *del_c; const char *line_prefix = ""; struct strbuf *msg = NULL; @@ -1269,7 +1269,6 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) /* Find the longest filename and max number of changes */ reset = diff_get_color_opt(options, DIFF_RESET); - set = diff_get_color_opt(options, DIFF_PLAIN); add_c = diff_get_color_opt(options, DIFF_FILE_NEW); del_c = diff_get_color_opt(options, DIFF_FILE_OLD); diff --git a/merge-recursive.c b/merge-recursive.c index c8343d70fe..7c12673553 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -357,7 +357,6 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o, */ const char *last_file = NULL; int last_len = 0; - struct stage_data *last_e; int i; /* @@ -394,7 +393,6 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o, if (S_ISREG(e->stages[2].mode) || S_ISLNK(e->stages[2].mode)) { last_file = path; last_len = len; - last_e = e; } else { last_file = NULL; } @@ -969,7 +967,6 @@ static int process_renames(struct merge_options *o, } for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) { - char *src; struct string_list *renames1, *renames2Dst; struct rename *ren1 = NULL, *ren2 = NULL; const char *branch1, *branch2; @@ -1004,7 +1001,6 @@ static int process_renames(struct merge_options *o, ren2 = ren1; ren1 = tmp; } - src = ren1->pair->one->path; ren1->dst_entry->processed = 1; ren1->src_entry->processed = 1; diff --git a/reachable.c b/reachable.c index a03fabf060..3fc6b1d320 100644 --- a/reachable.c +++ b/reachable.c @@ -70,16 +70,11 @@ static void process_tree(struct tree *tree, static void process_tag(struct tag *tag, struct object_array *p, const char *name) { struct object *obj = &tag->object; - struct name_path me; if (obj->flags & SEEN) return; obj->flags |= SEEN; - me.up = NULL; - me.elem = "tag:/"; - me.elem_len = 5; - if (parse_tag(tag) < 0) die("bad tag object %s", sha1_to_hex(obj->sha1)); if (tag->tagged) diff --git a/test-subprocess.c b/test-subprocess.c index 667d3e5079..8926bc52a9 100644 --- a/test-subprocess.c +++ b/test-subprocess.c @@ -3,11 +3,10 @@ int main(int argc, char **argv) { - const char *prefix; struct child_process cp; int nogit = 0; - prefix = setup_git_directory_gently(&nogit); + setup_git_directory_gently(&nogit); if (nogit) die("No git repo found"); if (!strcmp(argv[1], "--setup-work-tree")) { diff --git a/transport-helper.c b/transport-helper.c index 0c5b1bd994..a4f40fb6dc 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -561,10 +561,9 @@ static int push_refs_with_push(struct transport *transport, int mirror = flags & TRANSPORT_PUSH_MIRROR; struct helper_data *data = transport->data; struct strbuf buf = STRBUF_INIT; - struct child_process *helper; struct ref *ref; - helper = get_helper(transport); + get_helper(transport); if (!data->push) return 1; From c6b028d1a47c4bdb0c6e6bea6d64799dc11fd212 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 12:40:09 +0100 Subject: [PATCH 1774/3720] Actually use retval This is most likely a bug. Nocited by gcc 4.6.0. Signed-off-by: Johannes Schindelin --- tree-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree-diff.c b/tree-diff.c index 3954281f50..9e2dc7056f 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -58,7 +58,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } strbuf_setlen(base, old_baselen); - return 0; + return retval; } /* A whole sub-tree went away or appeared */ From cec1f26c043c5c79ff9184ec9ce649e75b2124f7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 19:22:11 +0100 Subject: [PATCH 1775/3720] fixup! Actually use retval Junio says this is wrong. This reverts commit c6b028d1a47c4bdb0c6e6bea6d64799dc11fd212. --- tree-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree-diff.c b/tree-diff.c index 9e2dc7056f..3954281f50 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -58,7 +58,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } strbuf_setlen(base, old_baselen); - return retval; + return 0; } /* A whole sub-tree went away or appeared */ From 10bb4d0fcd89b7bc4b42da829164ea894e2ce8f5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 19:24:42 +0100 Subject: [PATCH 1776/3720] fixup! Remove unused variables --- tree-diff.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tree-diff.c b/tree-diff.c index 3954281f50..76f83fcc27 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -17,7 +17,6 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; int old_baselen = base->len; - int retval = 0; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); @@ -53,7 +52,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, sha1, sha2, base->buf, 0, 0); } strbuf_addch(base, '/'); - retval = diff_tree_sha1(sha1, sha2, base->buf, opt); + diff_tree_sha1(sha1, sha2, base->buf, opt); } else { opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } From 2f27b6ffb81829e855e97c1704713d034baee29c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 19:32:27 +0100 Subject: [PATCH 1777/3720] fixup! Add a few more values for receive.denyCurrentBranch --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 36f0da37f7..b947bd60e1 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -351,7 +351,7 @@ static void merge_worktree(unsigned char *sha1) if (is_bare_repository()) die ("denyCurrentBranch = updateInstead needs a worktree"); - strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir())); env[0] = git_env.buf; env[1] = NULL; From 33c33cac4632a2cbf97834e764a969b7210be740 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 22 Mar 2011 15:56:45 -0700 Subject: [PATCH 1778/3720] add: make "add -u/-A" update full tree without pathspec When -u was introduced in dfdac5d (git-add -u: match the index with working tree., 2007-04-20), "add -u" (without pathspec) added everything. Shortly after, 2ed2c22 (git-add -u paths... now works from subdirectory, 2007-08-16) broke it while fixing something related. This makes -u and -A inconsistent with some other options, namely -p. It's been four years since the unintentional breakage and people are probably used to "git add -u" updating only current directory. Let's plan in 1.8.0 to change its behaviour in such a way that does not hurt existing users too badly during the transition period. - A new add.treewideupdate configuration variable can be set to "true" to make "add -u/-A" that is ran without any pathspec from a subdirectory to affect the whole tree. When the variable is set to "false", the operation is limited to the current working directory. - Missing configuration variable means the same thing as setting it to "false" for now, but the user will be given a warning about the transition plan, and an advise to either set the variable or to say "." - In 1.8.0, the warning message needs to be rephrased, the added test needs to be updated, and the default value for the variable needs to be flipped to "true". In a few releases after that, we would remove the warning message. Signed-off-by: Junio C Hamano --- builtin/add.c | 47 ++++++++++++++++++++++++++++++++++++----- t/t2200-add-update.sh | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/builtin/add.c b/builtin/add.c index e127d5a68b..595f5cc389 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -310,6 +310,7 @@ static const char ignore_error[] = static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0; static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0; +static int default_tree_wide_update = -1; static struct option builtin_add_options[] = { OPT__DRY_RUN(&show_only, "dry run"), @@ -335,6 +336,10 @@ static int add_config(const char *var, const char *value, void *cb) ignore_add_errors = git_config_bool(var, value); return 0; } + if (!strcasecmp(var, "add.treewideupdate")) { + default_tree_wide_update = git_config_bool(var, value); + return 0; + } return git_default_config(var, value, cb); } @@ -359,6 +364,29 @@ static int add_files(struct dir_struct *dir, int flags) return exit_status; } +static const char *warn_add_uA_180_migration_msg[] = { + "In release 1.8.0, running 'git add -u' (or 'git add -A') from", + "a subdirectory without giving any pathspec WILL take effect", + "on the whole working tree, not just the part under the current", + "directory. You can set add.treewideupdate configuration variable", + "to 'false' to keep the current behaviour.", + "You can set the configuration variable to 'true' to make the", + "'git add -u/-A' command without pathspec take effect on the whole", + "working tree now. If you do so, you can use '.' at the end of", + "the command, e.g. 'git add -u .' when you want to limit the", + "operation to the current directory.", + "This warning will be issued until you set the configuration variable", + "to either 'true' or 'false'." +}; + +static int warn_180_migration(void) +{ + int i; + for (i = 0; i < ARRAY_SIZE(warn_add_uA_180_migration_msg); i++) + warning("%s", warn_add_uA_180_migration_msg[i]); + return 0; /* default to "no" (not tree-wide, i.e. local) */ +} + int cmd_add(int argc, const char **argv, const char *prefix) { int exit_status = 0; @@ -368,6 +396,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) int flags; int add_new_files; int require_pathspec; + int whole_tree_add = 0; char *seen = NULL; git_config(add_config, NULL); @@ -389,9 +418,13 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (!show_only && ignore_missing) die("Option --ignore-missing can only be used together with --dry-run"); if ((addremove || take_worktree_changes) && !argc) { - static const char *here[2] = { ".", NULL }; - argc = 1; - argv = here; + whole_tree_add = 1; + if (prefix) { + if (default_tree_wide_update < 0) + default_tree_wide_update = warn_180_migration(); + if (!default_tree_wide_update) + whole_tree_add = 0; + } } add_new_files = !take_worktree_changes && !refresh_only; @@ -406,12 +439,16 @@ int cmd_add(int argc, const char **argv, const char *prefix) (!(addremove || take_worktree_changes) ? ADD_CACHE_IGNORE_REMOVAL : 0)); - if (require_pathspec && argc == 0) { + if (require_pathspec && !(argc || whole_tree_add)) { fprintf(stderr, "Nothing specified, nothing added.\n"); fprintf(stderr, "Maybe you wanted to say 'git add .'?\n"); return 0; } - pathspec = validate_pathspec(argc, argv, prefix); + + if (whole_tree_add) + pathspec = NULL; + else + pathspec = validate_pathspec(argc, argv, prefix); if (read_cache() < 0) die("index file corrupt"); diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index 0692427cb6..7ac8b7024b 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -80,6 +80,55 @@ test_expect_success 'change gets noticed' ' ' +test_expect_success 'update from a subdirectory without pathspec (no config)' ' + # This test needs to be updated to expect the whole tree + # update after 1.8.0 migration. + test_might_fail git config --remove add.treewideupdate && + test_might_fail git reset check dir1 && + echo changed >check && + ( + cd dir1 && + echo even more >sub2 && + git add -u 2>../expect.warning + ) && + git diff-files --name-only dir1 check >actual && + echo check >expect && + test_cmp expect actual && + grep warning expect.warning +' + +test_expect_success 'update from a subdirectory without pathspec (local)' ' + test_when_finished "git config --remove add.treewideupdate; :" && + git config add.treewideupdate false && + test_might_fail git reset check dir1 && + echo changed >check && + ( + cd dir1 && + echo even more >sub2 && + git add -u 2>../expect.warning + ) && + git diff-files --name-only dir1 check >actual && + echo check >expect && + test_cmp expect actual && + ! grep warning expect.warning +' + +test_expect_success 'update from a subdirectory without pathspec (global)' ' + test_when_finished "git config --remove add.treewideupdate; :" && + git config add.treewideupdate true && + test_might_fail git reset check dir1 && + echo changed >check && + ( + cd dir1 && + echo even more >sub2 && + git add -u 2>../expect.warning + ) && + git diff-files --name-only dir1 check >actual && + : >expect && + test_cmp expect actual && + ! grep warning expect.warning +' + test_expect_success SYMLINKS 'replace a file with a symlink' ' rm foo && From 939c1e623843f69db82f9ab4b74ee5e9914c1a2a Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 25 Mar 2011 12:03:26 -0400 Subject: [PATCH 1779/3720] t3030: fix accidental success in symlink rename In this test, we have merge two branches. On one branch, we renamed "a" to "e". On the other, we renamed "a" to "e" and then added a symlink pointing at "a" pointing to "e". The results for the test indicate that the merge should succeed, but also that "a" should no longer exist. Since both sides renamed "a" to the same destination, we will end up comparing those destinations for content. But what about what's left? One side (the rename only), replaced "a" with nothing. The other side replaced it with a symlink. The common base must also be nothing, because any "a" before this was meaningless (it was totally unrelated content that ended up getting renamed). The only sensible resolution is to keep the symlink. The rename-only side didn't touch the content versus the common base, and the other side added content. The 3-way merge dictates that we take the side with a change. And this gives the overall merge an intuitive result. One side made one change (a rename), and the other side made two changes: an identical rename, and an addition (that just happened to be at the same spot). The end result should contain both changes. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t3030-merge-recursive.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index 34794f8a70..e686f04623 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -267,7 +267,8 @@ test_expect_success 'setup 8' ' ln -s e a && git add a e && test_tick && - git commit -m "rename a->e, symlink a->e" + git commit -m "rename a->e, symlink a->e" && + oln=`printf e | git hash-object --stdin` fi ' @@ -630,16 +631,18 @@ test_expect_success 'merge-recursive copy vs. rename' ' if test_have_prereq SYMLINKS then - test_expect_success 'merge-recursive rename vs. rename/symlink' ' + test_expect_failure 'merge-recursive rename vs. rename/symlink' ' git checkout -f rename && git merge rename-ln && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( + echo "120000 blob $oln a" echo "100644 blob $o0 b" echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" echo "100644 blob $o0 e" + echo "120000 $oln 0 a" echo "100644 $o0 0 b" echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" From 103e404e9d0b3b8056b2ce4a89ba0516e2758fc6 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 25 Mar 2011 12:06:47 -0400 Subject: [PATCH 1780/3720] merge: handle renames with replacement content We generally think of a rename as removing one path entirely and placing similar content at a new path. In other words, after a rename, the original path is now empty. But that is not necessarily the case with rewrite detection (which is not currently possible to do for merge-recursive). The current merge code blindly removes paths that are used as rename sources; however, we should check to see if there is useful content at that path. There are basically two interesting cases: 1. One side renames a path, but also puts new content (or a symlink) at the same path. We want to detect the rename, and have changes from the other side applied to the rename destination. The new content at the original path should be left untouched. The current code just calls remove_file, but that ignores the concept that the renaming side may put something else useful there. We should detect this case and either remove (if no new content), or put the new content in place at the original path. 2. Both sides renamed and installed new content at the original path. If they didn't rename to the same destination, it is a conflict, and we already mark it as such. But if it's the same destination, then it's not a conflict; the renamed content will be merged at the new destination. For the new content at the original path, we have to do a 3-way merge. The base must be the null sha1, because this "slot" for content didn't exist before (it was taken up by the content which got renamed away). So if only one side installed new content, that content automatically wins. If both sides did, and it is the same content, then that content is OK. But if the content is different, then we have a conflict and should do the usual conflict-markers thing. This patch implements the semantics described above, which lays the groundwork for turning on rewrite detection. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- merge-recursive.c | 65 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 42d52cb5bc..999892e03c 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -712,6 +712,64 @@ static void update_file(struct merge_options *o, update_file_flags(o, sha, mode, path, o->call_depth || clean, !o->call_depth); } +static int update_or_remove(struct merge_options *o, + const unsigned char *sha1, unsigned mode, + const char *path, int update_wd) +{ + if (is_null_sha1(sha1)) + return remove_file(o, 1, path, !update_wd); + + update_file_flags(o, sha1, mode, path, 1, update_wd); + return 0; +} + +static void merge_rename_source(struct merge_options *o, + const char *path, + struct stage_data *d) +{ + if (is_null_sha1(d->stages[2].sha)) { + /* + * If both were real renames (not from a broken pair), we can + * stop caring about the path. We don't touch the working + * directory, though. The path must be gone in HEAD, so there + * is no point (and anything we did delete would be an + * untracked file). + */ + if (is_null_sha1(d->stages[3].sha)) { + remove_file(o, 1, path, 1); + return; + } + + /* + * If "ours" was a real rename, but the other side came + * from a broken pair, then their version is the right + * resolution (because we have no content, ours having been + * renamed away, and they have new content). + */ + update_file_flags(o, d->stages[3].sha, d->stages[3].mode, + path, 1, 1); + return; + } + + /* + * Now we have the opposite. "theirs" is a real rename, but ours + * is from a broken pair. We resolve in favor of us, but we don't + * need to touch the working directory. + */ + if (is_null_sha1(d->stages[3].sha)) { + update_file_flags(o, d->stages[2].sha, d->stages[2].mode, + path, 1, 0); + return; + } + + /* + * Otherwise, both came from broken pairs. We need to do an actual + * merge on the entries. We can just mark it as unprocessed and + * the regular code will handle it. + */ + d->processed = 0; +} + /* Low level file merging, update and removal */ struct merge_file_info { @@ -1031,7 +1089,7 @@ static int process_renames(struct merge_options *o, ren1->dst_entry, ren2->dst_entry); } else { - remove_file(o, 1, ren1_src, 1); + merge_rename_source(o, ren1_src, ren1->src_entry); update_stages_and_entry(ren1_dst, ren1->dst_entry, ren1->pair->one, @@ -1055,7 +1113,10 @@ static int process_renames(struct merge_options *o, int renamed_stage = a_renames == renames1 ? 2 : 3; int other_stage = a_renames == renames1 ? 3 : 2; - remove_file(o, 1, ren1_src, o->call_depth || renamed_stage == 2); + update_or_remove(o, + ren1->src_entry->stages[renamed_stage].sha, + ren1->src_entry->stages[renamed_stage].mode, + ren1_src, renamed_stage == 3); hashcpy(src_other.sha1, ren1->src_entry->stages[other_stage].sha); src_other.mode = ren1->src_entry->stages[other_stage].mode; From 63433a4706a2b7efd054eda5d042bf026529a7bb Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 25 Mar 2011 12:08:10 -0400 Subject: [PATCH 1781/3720] merge: turn on rewrite detection We currently don't do break-detection at all in merge-recursive. But there are some cases where it would provide a more useful merge result. For example, consider this case (which is the basis for the new tests in t6039): 1. You rename a header file foo.h to bar.h. You install a new foo.h that includes bar.h (for compatibility). 2. Another branch makes changes to foo.h. When you merge, you want the changes the other branch made to foo.h to migrate to the rename destination, bar.h, just as you would if you hadn't installed that compatibility header. Similarly, you want the compatibility header left untouched. The other side's changes all ended up in bar.h, so there is no reason to conflict with the new content in foo.h. This patch turns on break detection for merge-recursive. In addition to new tests in t6039, it makes a similar test in t3030 pass. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- merge-recursive.c | 1 + t/t3030-merge-recursive.sh | 2 +- t/t6039-merge-break.sh | 174 +++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100755 t/t6039-merge-break.sh diff --git a/merge-recursive.c b/merge-recursive.c index 999892e03c..986494e89a 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -435,6 +435,7 @@ static struct string_list *get_renames(struct merge_options *o, opts.rename_score = o->rename_score; opts.warn_on_too_large_rename = 1; opts.output_format = DIFF_FORMAT_NO_OUTPUT; + opts.break_opt = 0; if (diff_setup_done(&opts) < 0) die("diff setup failed"); diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts); diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index e686f04623..43ff220cfe 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -631,7 +631,7 @@ test_expect_success 'merge-recursive copy vs. rename' ' if test_have_prereq SYMLINKS then - test_expect_failure 'merge-recursive rename vs. rename/symlink' ' + test_expect_success 'merge-recursive rename vs. rename/symlink' ' git checkout -f rename && git merge rename-ln && diff --git a/t/t6039-merge-break.sh b/t/t6039-merge-break.sh new file mode 100755 index 0000000000..d3dabf5b85 --- /dev/null +++ b/t/t6039-merge-break.sh @@ -0,0 +1,174 @@ +#!/bin/sh + +test_description='merging with renames from broken pairs + +This is based on a real-world practice of moving a header file to a +new location, but installing a "replacement" file that points to +the old one. We need break detection in the merge to find the +rename. +' +. ./test-lib.sh + +# A fake header file; it needs a fair bit of content +# for break detection and inexact rename detection to work. +mksample() { + echo '#ifndef SAMPLE_H' + echo '#define SAMPLE_H' + for i in 0 1 2 3 4; do + for j in 0 1 2 3 4 5 6 7 8 9; do + echo "extern fun$i$j();" + done + done + echo '#endif /* SAMPLE_H */' +} + +mvsample() { + sed 's/SAMPLE_H/NEW_H/' "$1" >"$2" && + rm "$1" +} + +# A replacement sample header file that references a new one. +mkreplacement() { + echo '#ifndef SAMPLE_H' + echo '#define SAMPLE_H' + echo "#include \"$1\"" + echo '#endif /* SAMPLE_H */' +} + +# Tweak the header file in a minor way. +tweak() { + sed 's,42.*,& /* secret of something-or-other */,' "$1" >"$1.tmp" && + mv "$1.tmp" "$1" +} + +reset() { + git reset --hard && + git checkout master && + git reset --hard base && + git clean -f && + { git branch -D topic || true; } +} + +test_expect_success 'setup baseline' ' + mksample >sample.h && + git add sample.h && + git commit -m "add sample.h" && + git tag base +' + +setup_rename_plus_tweak() { + reset && + mvsample sample.h new.h && + mkreplacement new.h >sample.h && + git add sample.h new.h && + git commit -m 'rename sample.h to new.h, with replacement' && + git checkout -b topic base && + tweak sample.h && + git commit -a -m 'tweak sample.h' +} + +check_tweak_result() { + mksample >expect.orig && + mvsample expect.orig expect && + tweak expect && + test_cmp expect new.h && + mkreplacement new.h >expect && + test_cmp expect sample.h +} + +test_expect_success 'merge rename to tweak finds rename' ' + setup_rename_plus_tweak && + git merge master && + check_tweak_result +' + +test_expect_success 'merge tweak to rename finds rename' ' + setup_rename_plus_tweak && + git checkout master && + git merge topic && + check_tweak_result +' + +setup_double_rename_one_replacement() { + setup_rename_plus_tweak && + mvsample sample.h new.h && + git add new.h && + git commit -a -m 'rename sample.h to new.h (no replacement)' +} + +test_expect_success 'merge rename to rename/tweak (one replacement)' ' + setup_double_rename_one_replacement && + git merge master && + check_tweak_result +' + +test_expect_success 'merge rename/tweak to rename (one replacement)' ' + setup_double_rename_one_replacement && + git checkout master && + git merge topic && + check_tweak_result +' + +setup_double_rename_two_replacements_same() { + setup_rename_plus_tweak && + mvsample sample.h new.h && + mkreplacement new.h >sample.h && + git add sample.h new.h && + git commit -m 'rename sample.h to new.h with replacement (same)' +} + +test_expect_success 'merge rename to rename/tweak (two replacements, same)' ' + setup_double_rename_two_replacements_same && + git merge master && + check_tweak_result +' + +test_expect_success 'merge rename/tweak to rename (two replacements, same)' ' + setup_double_rename_two_replacements_same && + git checkout master && + git merge topic && + check_tweak_result +' + +setup_double_rename_two_replacements_diff() { + setup_rename_plus_tweak && + mvsample sample.h new.h && + mkreplacement diff.h >sample.h && + git add sample.h new.h && + git commit -m 'rename sample.h to new.h with replacement (diff)' +} + +test_expect_success 'merge rename to rename/tweak (two replacements, diff)' ' + setup_double_rename_two_replacements_diff && + test_must_fail git merge master && + cat >expect <<-\EOF && + #ifndef SAMPLE_H + #define SAMPLE_H + <<<<<<< HEAD + #include "diff.h" + ======= + #include "new.h" + >>>>>>> master + #endif /* SAMPLE_H */ + EOF + test_cmp expect sample.h +' + +test_expect_success 'merge rename to rename/tweak (two replacements, diff)' ' + setup_double_rename_two_replacements_diff && + git checkout master && + test_must_fail git merge topic && + cat >expect <<-\EOF && + #ifndef SAMPLE_H + #define SAMPLE_H + <<<<<<< HEAD + #include "new.h" + ======= + #include "diff.h" + >>>>>>> topic + #endif /* SAMPLE_H */ + EOF + test_cmp expect sample.h +' + +test_done From b8588714fabd14246a9c29ef33ad1b3dc23b12f7 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1782/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 62eccd3391..8d768ce3d6 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From 0ffe6bbffeed53009ce9008a9b6d95d03c2301f6 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1783/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 47f1c5f70f..3db23ca64a 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 6621e5671c..49be5becf4 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -327,6 +327,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 9f06d21579..88a9144172 100644 --- a/cache.h +++ b/cache.h @@ -577,6 +577,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 878b1de97c..92d4777f81 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 8d768ce3d6..06f4d3e0cc 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -309,6 +306,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 0abcada938..1e5cd7d601 100644 --- a/config.c +++ b/config.c @@ -660,6 +660,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index f4549d3f7b..6984119d01 100644 --- a/environment.c +++ b/environment.c @@ -56,6 +56,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 49b50eec86..25963ec7bd 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -566,4 +566,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 5524d02740bea9158c3873059d2aab25a1a0a569 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1784/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 92d4777f81..a9564ee332 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 9c2177b1492a993ac274239f02a9301815af21d0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1785/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 65eab8e824301b2adacc8d286e096b2acb0344aa Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1786/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index fd6a43d0a2..3c6dab147e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,9 +1269,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2079,7 +2076,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2091,12 +2088,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2117,18 +2121,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2149,20 +2150,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 2b0c49ca620130e1177905ab42083d7d1e02123e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1787/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 3c6dab147e..c5037685e3 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 356eae3763aab8516ecf10dbd6d93327924803ed Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1788/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index e82c6bfede..ca92f60b14 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9478,7 +9478,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From a93680daba25a9ee904681481777794df43d701d Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1789/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 0ee9f17993..6c8e965658 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -371,4 +371,32 @@ test_expect_success 'init prefers command line to GIT_DIR' ' ! test -d otherdir/refs ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From c383aeac80c3dd5ac6219a8c7a5c79864ffb94e5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1790/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a93e70fac4..bd1c377319 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -734,6 +734,10 @@ EOF test_expect_success C_LOCALE_OUTPUT 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -750,6 +754,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -779,8 +787,16 @@ test_expect_success 'status submodule summary (clean submodule): commit' ' test_expect_success C_LOCALE_OUTPUT 'status submodule summary (clean submodule): output' ' git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -795,6 +811,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -830,6 +850,10 @@ EOF test_expect_success C_LOCALE_OUTPUT 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From a42591794e435ddd6b202f227cec1b27f65d2809 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1791/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 3db23ca64a..953cb3ba6e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1646,6 +1646,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 27050e7c16..5a30fd7a1a 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 31b9b23716a0d29d7cdd0e5b1f5821e3a13eed94 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1792/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From e0eb256dda636fe48d34ff89ca469e1d999cf07f Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1793/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 63f6dff034ab525d5ae8cf2c6606abd3c11f9c24 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1794/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 3e3c528497..5ae76049f7 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index a9564ee332..cb902a342c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1797,3 +1797,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index 06f4d3e0cc..1f754aed3b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -340,3 +340,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 1e5cd7d601..ede6007687 100644 --- a/config.c +++ b/config.c @@ -872,7 +872,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 25963ec7bd..a69b634c16 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -570,4 +570,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 4d73cc9cd2..39b576c298 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 8cb21402af8628df48638cc6d14ce856a3e38aa3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1795/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 033c0b974368008356adccd486cbbcdcb70371fd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1796/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6cdd5910db..b312da10d8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -513,7 +513,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -682,7 +683,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -755,7 +757,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -779,7 +781,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 2308444cc2acb4f517dae3fe12bd93bc41bcb5a6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1797/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index abc47f3abc..8a378c38bf 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 9cbf5546b71e382a7bf6d725472bb1ec64db50b5 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1798/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 88a9144172..c730c58ca0 100644 --- a/cache.h +++ b/cache.h @@ -749,7 +749,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index cb902a342c..67a7a1d8e6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1815,3 +1815,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 1f754aed3b..a37b2718d5 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -300,6 +300,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index a69b634c16..d04ed16a93 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -210,6 +210,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 39b576c298..8745aad206 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From dff143c4023e7cbb6033c0ea3a2312a6c56d7c4e Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1799/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5ae76049f7..9bf63d8c8a 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 9eb3267facb83dbd5468750a4e35777bdc2e72ca Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1800/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 67a7a1d8e6..48a3b760d9 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1818,23 +1818,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From de9e3da43860bd7479879fce4dcdf041e11f3bb3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1801/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index c5037685e3..0d5bd3465f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From c98de34a1b780c01daf14c47a878436f0c8828ae Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1802/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index ca92f60b14..c5799caeca 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9478,18 +9478,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9500,6 +9489,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From d446dea51d41c9ddcec128a6d1e79ea9f683f9f6 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1803/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 48a3b760d9..318c6560ec 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -668,11 +668,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 46a8d2b06bc013896b93ab4684f7d11b492d6817 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1804/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index a37b2718d5..9155ce3af2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From b7aa9ab9a2c45cfb3a405f42cae517460396f01e Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1805/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 360ec683af00c238ad919637567d79dd0edc6fb0 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1806/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From aac2c52bcffd7f61a08a3ca10414d856af9eace3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1807/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index 2a1e3a94c9..59133640f4 100644 --- a/log-tree.c +++ b/log-tree.c @@ -506,7 +506,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 700308f8d3d7ef0bd854f35f61b9cec5ea29a52e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1808/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ee69ea683a..dc3cb8e9a5 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4026,6 +4026,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 5346471e96dbdc74a373aa79fffd8654badd7246 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1809/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index dc3cb8e9a5..4049ccd973 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4041,7 +4041,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 1904881b12112a10f07c51b814144beb99efb3fc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1810/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 3e487ff2806a3a99ae35274c450512f1a46f123b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1811/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index d39a6ab930..9324b4ddc9 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -278,6 +278,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die (_("Could not open '%s' for writing."), file); From e6484efd6ab13be412350f7a32abf6f52563be7e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1812/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 5a30fd7a1a..b947bd60e1 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 2a774a320ac105c2f1cc5af080f09fdc57a1ffe8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1813/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 5b8f30d3ed..402a35595c 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -178,6 +179,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -188,6 +205,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -492,6 +512,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -907,6 +930,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); From c2d103135a5a643833871f7d4bd4bfc7e6c933c5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1814/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 53fd282cf4..5651503adf 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 37c57a9d4dc59de5c194be26f77c8eab7eb9d19d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1815/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 318c6560ec..6750e672f4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1803,7 +1803,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From 3d6b89c7f4207e0ec14436a9f437ae482d525eb0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1816/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5651503adf..cf1caf0853 100644 --- a/Makefile +++ b/Makefile @@ -1884,7 +1884,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1924,6 +1924,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From 7cc8ecec5b140bc6feb7797a9eba4aadabae8835 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1817/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index da6252b117..4b7236abcf 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -340,6 +340,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From 75482e4d5c08f924a56e25226d5c2cadc6a5b656 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 1818/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 402a35595c..fcb568024f 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1002,6 +1002,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From f28cde3d9e4cb87b46f92880fa5ee57ec73d2e7d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 1819/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index fcb568024f..d575efec11 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1002,7 +1002,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From ce82269e606de7bba867d098939c0a006f38aeed Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 1820/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From 3afaf64318d81d32478e919421b9fda7c0e7cede Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1821/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6750e672f4..d52756254a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 522d9c70e91108da886807c2a633b2684c4e1216 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 12:39:31 +0100 Subject: [PATCH 1822/3720] Remove unused variables Noticed by gcc 4.6.0. Signed-off-by: Johannes Schindelin --- merge-recursive.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index c8343d70fe..7c12673553 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -357,7 +357,6 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o, */ const char *last_file = NULL; int last_len = 0; - struct stage_data *last_e; int i; /* @@ -394,7 +393,6 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o, if (S_ISREG(e->stages[2].mode) || S_ISLNK(e->stages[2].mode)) { last_file = path; last_len = len; - last_e = e; } else { last_file = NULL; } @@ -969,7 +967,6 @@ static int process_renames(struct merge_options *o, } for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) { - char *src; struct string_list *renames1, *renames2Dst; struct rename *ren1 = NULL, *ren2 = NULL; const char *branch1, *branch2; @@ -1004,7 +1001,6 @@ static int process_renames(struct merge_options *o, ren2 = ren1; ren1 = tmp; } - src = ren1->pair->one->path; ren1->dst_entry->processed = 1; ren1->src_entry->processed = 1; From 0fc1a422e94cb54e499b4e5e2a7625b5cab2698e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 09:29:35 +0200 Subject: [PATCH 1823/3720] MinGW: Skip test redirecting to fd 4 ... because that does not work in MinGW. Signed-off-by: Johannes Schindelin --- t/t0081-line-buffer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index 1dbe1c9b08..199773bc1a 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -131,7 +131,7 @@ test_expect_success PIPE,EXPENSIVE 'longer read (around 65536 bytes)' ' long_read_test 65536 ' -test_expect_success 'read from file descriptor' ' +test_expect_success NOT_MINGW 'read from file descriptor' ' rm -f input && echo hello >expect && echo hello >input && From acc773ba5c5bc838af47acb8154e9d4d0bbdcb68 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 16:44:45 +0200 Subject: [PATCH 1824/3720] Disable test on MinGW that challenges its bash quoting Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index d189add2d0..dfd79cf68b 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -815,7 +815,10 @@ test_expect_success 'remote set-url --add bbb' ' ' test_expect_success 'remote set-url --delete .*' ' - test_must_fail git remote set-url --delete someremote .\* && + if test_have_prereq NOT_MINGW + then + test_must_fail git remote set-url --delete someremote .\* + fi && echo "YYY" >expect && echo baz >>expect && echo bbb >>expect && From 14b47695e9a6d8ecb28453ad75086886f486acf7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 6 Apr 2011 17:25:44 -0700 Subject: [PATCH 1825/3720] add -u: get rid of "treewideupdate" configuration Thanks to the magic ":/" pathspec, it is much easier to invoke both tree-wide operation and limited-to-cwd operation on demand from the command line. Only the downside of the configuration variable, namely, it makes git behave differently depending on who you are and in which repository you are using it, hence making it harder to help and/or teach others, remains. Remove the configuration variable, and adjust the warning message. Signed-off-by: Junio C Hamano --- builtin/add.c | 26 ++++++-------------------- t/t2200-add-update.sh | 29 +++++++++++++++++++---------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/builtin/add.c b/builtin/add.c index 595f5cc389..f58d1cfd22 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -310,7 +310,6 @@ static const char ignore_error[] = static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0; static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0; -static int default_tree_wide_update = -1; static struct option builtin_add_options[] = { OPT__DRY_RUN(&show_only, "dry run"), @@ -336,10 +335,6 @@ static int add_config(const char *var, const char *value, void *cb) ignore_add_errors = git_config_bool(var, value); return 0; } - if (!strcasecmp(var, "add.treewideupdate")) { - default_tree_wide_update = git_config_bool(var, value); - return 0; - } return git_default_config(var, value, cb); } @@ -368,15 +363,10 @@ static const char *warn_add_uA_180_migration_msg[] = { "In release 1.8.0, running 'git add -u' (or 'git add -A') from", "a subdirectory without giving any pathspec WILL take effect", "on the whole working tree, not just the part under the current", - "directory. You can set add.treewideupdate configuration variable", - "to 'false' to keep the current behaviour.", - "You can set the configuration variable to 'true' to make the", - "'git add -u/-A' command without pathspec take effect on the whole", - "working tree now. If you do so, you can use '.' at the end of", - "the command, e.g. 'git add -u .' when you want to limit the", - "operation to the current directory.", - "This warning will be issued until you set the configuration variable", - "to either 'true' or 'false'." + "directory. Please make it a habit to add '.' when you want to", + "limit the operation to the current directory and below.", + "You can use ':/' at the end of the command to affect the operation", + "on the whole working tree.", }; static int warn_180_migration(void) @@ -419,12 +409,8 @@ int cmd_add(int argc, const char **argv, const char *prefix) die("Option --ignore-missing can only be used together with --dry-run"); if ((addremove || take_worktree_changes) && !argc) { whole_tree_add = 1; - if (prefix) { - if (default_tree_wide_update < 0) - default_tree_wide_update = warn_180_migration(); - if (!default_tree_wide_update) - whole_tree_add = 0; - } + if (prefix) + whole_tree_add = warn_180_migration(); } add_new_files = !take_worktree_changes && !refresh_only; diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index 7ac8b7024b..f7711ba46c 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -80,10 +80,9 @@ test_expect_success 'change gets noticed' ' ' -test_expect_success 'update from a subdirectory without pathspec (no config)' ' +test_expect_success 'update from a subdirectory without pathspec' ' # This test needs to be updated to expect the whole tree # update after 1.8.0 migration. - test_might_fail git config --remove add.treewideupdate && test_might_fail git reset check dir1 && echo changed >check && ( @@ -97,15 +96,13 @@ test_expect_success 'update from a subdirectory without pathspec (no config)' ' grep warning expect.warning ' -test_expect_success 'update from a subdirectory without pathspec (local)' ' - test_when_finished "git config --remove add.treewideupdate; :" && - git config add.treewideupdate false && +test_expect_success 'update from a subdirectory with local pathspec' ' test_might_fail git reset check dir1 && echo changed >check && ( cd dir1 && echo even more >sub2 && - git add -u 2>../expect.warning + git add -u . 2>../expect.warning ) && git diff-files --name-only dir1 check >actual && echo check >expect && @@ -113,15 +110,27 @@ test_expect_success 'update from a subdirectory without pathspec (local)' ' ! grep warning expect.warning ' -test_expect_success 'update from a subdirectory without pathspec (global)' ' - test_when_finished "git config --remove add.treewideupdate; :" && - git config add.treewideupdate true && +test_expect_success 'update from a subdirectory with magic pathspec (mnemonic)' ' test_might_fail git reset check dir1 && echo changed >check && ( cd dir1 && echo even more >sub2 && - git add -u 2>../expect.warning + git add -u :/ 2>../expect.warning + ) && + git diff-files --name-only dir1 check >actual && + : >expect && + test_cmp expect actual && + ! grep warning expect.warning +' + +test_expect_success 'update from a subdirectory with magic pathspec (longhand)' ' + test_might_fail git reset check dir1 && + echo changed >check && + ( + cd dir1 && + echo even more >sub2 && + git add -u ":(top)" 2>../expect.warning ) && git diff-files --name-only dir1 check >actual && : >expect && From 597cae6c102262eea7548b927a86dee199518e29 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 8 Apr 2011 16:23:07 -0700 Subject: [PATCH 1826/3720] Revert "add -u" default change plans This reverts commit 14b47695e9a6d8ecb28453ad75086886f486acf7 and 33c33cac4632a2cbf97834e764a969b7210be740, as we decided not to change the default behaviour of "add -u" when run from a subdirectory without any pathspec for now. --- builtin/add.c | 33 ++++-------------------- t/t2200-add-update.sh | 58 ------------------------------------------- 2 files changed, 5 insertions(+), 86 deletions(-) diff --git a/builtin/add.c b/builtin/add.c index f58d1cfd22..e127d5a68b 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -359,24 +359,6 @@ static int add_files(struct dir_struct *dir, int flags) return exit_status; } -static const char *warn_add_uA_180_migration_msg[] = { - "In release 1.8.0, running 'git add -u' (or 'git add -A') from", - "a subdirectory without giving any pathspec WILL take effect", - "on the whole working tree, not just the part under the current", - "directory. Please make it a habit to add '.' when you want to", - "limit the operation to the current directory and below.", - "You can use ':/' at the end of the command to affect the operation", - "on the whole working tree.", -}; - -static int warn_180_migration(void) -{ - int i; - for (i = 0; i < ARRAY_SIZE(warn_add_uA_180_migration_msg); i++) - warning("%s", warn_add_uA_180_migration_msg[i]); - return 0; /* default to "no" (not tree-wide, i.e. local) */ -} - int cmd_add(int argc, const char **argv, const char *prefix) { int exit_status = 0; @@ -386,7 +368,6 @@ int cmd_add(int argc, const char **argv, const char *prefix) int flags; int add_new_files; int require_pathspec; - int whole_tree_add = 0; char *seen = NULL; git_config(add_config, NULL); @@ -408,9 +389,9 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (!show_only && ignore_missing) die("Option --ignore-missing can only be used together with --dry-run"); if ((addremove || take_worktree_changes) && !argc) { - whole_tree_add = 1; - if (prefix) - whole_tree_add = warn_180_migration(); + static const char *here[2] = { ".", NULL }; + argc = 1; + argv = here; } add_new_files = !take_worktree_changes && !refresh_only; @@ -425,16 +406,12 @@ int cmd_add(int argc, const char **argv, const char *prefix) (!(addremove || take_worktree_changes) ? ADD_CACHE_IGNORE_REMOVAL : 0)); - if (require_pathspec && !(argc || whole_tree_add)) { + if (require_pathspec && argc == 0) { fprintf(stderr, "Nothing specified, nothing added.\n"); fprintf(stderr, "Maybe you wanted to say 'git add .'?\n"); return 0; } - - if (whole_tree_add) - pathspec = NULL; - else - pathspec = validate_pathspec(argc, argv, prefix); + pathspec = validate_pathspec(argc, argv, prefix); if (read_cache() < 0) die("index file corrupt"); diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index f7711ba46c..0692427cb6 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -80,64 +80,6 @@ test_expect_success 'change gets noticed' ' ' -test_expect_success 'update from a subdirectory without pathspec' ' - # This test needs to be updated to expect the whole tree - # update after 1.8.0 migration. - test_might_fail git reset check dir1 && - echo changed >check && - ( - cd dir1 && - echo even more >sub2 && - git add -u 2>../expect.warning - ) && - git diff-files --name-only dir1 check >actual && - echo check >expect && - test_cmp expect actual && - grep warning expect.warning -' - -test_expect_success 'update from a subdirectory with local pathspec' ' - test_might_fail git reset check dir1 && - echo changed >check && - ( - cd dir1 && - echo even more >sub2 && - git add -u . 2>../expect.warning - ) && - git diff-files --name-only dir1 check >actual && - echo check >expect && - test_cmp expect actual && - ! grep warning expect.warning -' - -test_expect_success 'update from a subdirectory with magic pathspec (mnemonic)' ' - test_might_fail git reset check dir1 && - echo changed >check && - ( - cd dir1 && - echo even more >sub2 && - git add -u :/ 2>../expect.warning - ) && - git diff-files --name-only dir1 check >actual && - : >expect && - test_cmp expect actual && - ! grep warning expect.warning -' - -test_expect_success 'update from a subdirectory with magic pathspec (longhand)' ' - test_might_fail git reset check dir1 && - echo changed >check && - ( - cd dir1 && - echo even more >sub2 && - git add -u ":(top)" 2>../expect.warning - ) && - git diff-files --name-only dir1 check >actual && - : >expect && - test_cmp expect actual && - ! grep warning expect.warning -' - test_expect_success SYMLINKS 'replace a file with a symlink' ' rm foo && From fc4f0303701a284a945af6931cd9be7159317c3c Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1827/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 62eccd3391..8d768ce3d6 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From 2f5637e6092b743e6df9b6a8bb78ac790cab85dc Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1828/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 480dd0a861..8595205ab2 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index ba13a54793..4226c6e782 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 5b896d9845..2c838f94fc 100644 --- a/cache.h +++ b/cache.h @@ -579,6 +579,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 4423961768..c4229d9266 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 8d768ce3d6..06f4d3e0cc 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -309,6 +306,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 5f9ec28945..52c72f97fa 100644 --- a/config.c +++ b/config.c @@ -664,6 +664,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 40185bc854..901d5501d6 100644 --- a/environment.c +++ b/environment.c @@ -57,6 +57,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index e0bb81ed8d..b3e6824fc2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -569,4 +569,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 8c7a07504ca1da8702db8f0c966253ccb0846299 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1829/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index c4229d9266..751ed8253a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 2cf35476461662f61a795486133dc6d3bcf92dc1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1830/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 7c8a42b1e2401f501ba03b034193201796c13950 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1831/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index fd6a43d0a2..3c6dab147e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,9 +1269,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2079,7 +2076,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2091,12 +2088,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2117,18 +2121,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2149,20 +2150,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 0f327adb10e8807c8f4ef5cd128fd01a7247189d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1832/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 3c6dab147e..c5037685e3 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 654899acdb9abdf058c9b12c5d5bdf35adbe606e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1833/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 4cde0c493b..6b18e34726 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9480,7 +9480,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 0489c6e7420d28fb7a9ca2d78c94c8eb023545f7 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1834/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 54520f6fa6..d4f90f61c2 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' ! test -d newdir/here ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 3aaf07396fe7cd44fc08eccad9c12bb2a2358af8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1835/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a93e70fac4..bd1c377319 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -734,6 +734,10 @@ EOF test_expect_success C_LOCALE_OUTPUT 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -750,6 +754,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -779,8 +787,16 @@ test_expect_success 'status submodule summary (clean submodule): commit' ' test_expect_success C_LOCALE_OUTPUT 'status submodule summary (clean submodule): output' ' git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -795,6 +811,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -830,6 +850,10 @@ EOF test_expect_success C_LOCALE_OUTPUT 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From c536298b7eeb77e9642878d65f029c8edc6353da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1836/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 8595205ab2..a90b1bce3f 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1599,6 +1599,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e1ba4dc697..e2210f9900 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 5fa187f8b609b72661d4d8dbc0271b15e1c48b42 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1837/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 8e2f232001cd386868e4066aab09e9e7fc1eed80 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1838/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From f10a7a17d5d966c9727b1511d8871d51aa2a222f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1839/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 3e3c528497..5ae76049f7 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 751ed8253a..cf74e8948c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1797,3 +1797,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index 06f4d3e0cc..1f754aed3b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -340,3 +340,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 52c72f97fa..097bfa8cfd 100644 --- a/config.c +++ b/config.c @@ -876,7 +876,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index b3e6824fc2..927deb0bf2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -573,4 +573,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 4d73cc9cd2..39b576c298 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 0bd8b0ecd9f0a92f0da31221ad50544af87bc14a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1840/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 7ab0f16165b7a00a9706b5d395e3b6b6dd314227 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1841/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6cdd5910db..b312da10d8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -513,7 +513,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -682,7 +683,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -755,7 +757,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -779,7 +781,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 3be1875a90e90fa7662c888f2a5af9a7a95f5d70 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1842/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 3e7c2bb726..2020d365d4 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 1a55ed5a9366a1923ec77ed1fd73d98c01a86276 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1843/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 2c838f94fc..e925bb424c 100644 --- a/cache.h +++ b/cache.h @@ -751,7 +751,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index cf74e8948c..4b4b958fb5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1815,3 +1815,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 1f754aed3b..a37b2718d5 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -300,6 +300,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 927deb0bf2..1dda551350 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -211,6 +211,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 39b576c298..8745aad206 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 4164f20d80a2d8512d4d0ebb204af82ea4e694ba Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1844/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5ae76049f7..9bf63d8c8a 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 427fbd1d61025ed8f4412409fd69d8f7fe4e25de Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1845/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b4b958fb5..688c7f3a8f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1818,23 +1818,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From a72e7801d3e8248153643fe12ad2589bc2d7171e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1846/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index c5037685e3..0d5bd3465f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 38d35762b74b86f4f2352a819acec46f4272ac38 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1847/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 6b18e34726..2a92e20f06 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9480,18 +9480,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9502,6 +9491,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From a8b6eb536790a9c1cdc796ca43fbeb3011a5b170 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1848/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 688c7f3a8f..e82a3bd123 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -668,11 +668,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From c445d76a13858a2c045ac18fb5c088489ddea8bc Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1849/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index a37b2718d5..9155ce3af2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From f482966e0323577d9caba23548d544abc154df33 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1850/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 2896f530c28a451bcb570fd114b8505451612733 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1851/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From a253e1807128e26dfa49306d08d1a6aa323f1e0f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1852/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index 2a1e3a94c9..59133640f4 100644 --- a/log-tree.c +++ b/log-tree.c @@ -506,7 +506,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 1ea839c0c1769b03d7a2385838e33d634bf54692 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1853/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ee69ea683a..dc3cb8e9a5 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4026,6 +4026,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 95df86692e54252be92fb6860a9b4d571e266f3e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1854/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index dc3cb8e9a5..4049ccd973 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4041,7 +4041,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 8a4b6e543559aabe2a68f8738b0ff7f0df3ea482 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1855/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 4d17a478922805b93ba3ae51d585ee104bd528a4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1856/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index d39a6ab930..9324b4ddc9 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -278,6 +278,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die (_("Could not open '%s' for writing."), file); From 8e6159570f6d8ea2a2ccce707d69f40bbfeffd26 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1857/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e2210f9900..2374ebea60 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From b584bfcdb9ca2fa1a92f69e215d1ef9820f10ad4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1858/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 3ee2ec51de..9a4e42b9c0 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -178,6 +179,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -188,6 +205,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -505,6 +525,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -920,6 +943,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); From 10a13c4eb48e47da12a89578934a5b3ce7fb1394 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1859/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dbe618bef8..e01ea0c336 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 38dc859fb184a00bfbe18e21dced027f221971f8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1860/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e82a3bd123..bb4bfb2084 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1803,7 +1803,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From c9dcf6530f1381e1301858a5d4a652473ba7dcd3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1861/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e01ea0c336..74156aeea9 100644 --- a/Makefile +++ b/Makefile @@ -1884,7 +1884,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1924,6 +1924,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From 29141a4b84208444b2c4adb7b6fea83f25f2a602 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1862/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index da6252b117..4b7236abcf 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -340,6 +340,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From be0e82b1d91d064d26e8a076ad0e19f988057b17 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 1863/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 9a4e42b9c0..c9121b2249 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1015,6 +1015,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From 8d05952758fbdbf8001f2d9dbe550aa0317d7acf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 1864/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index c9121b2249..a5b620c60b 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1015,7 +1015,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From 0f57674f13493bf7e5e8710475cdb3d3f8fbb5b6 Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 1865/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From d13b63b0b6e64e80b784a59299e2479169f260cd Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1866/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index bb4bfb2084..6b3a8cf699 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 01bcfd72d07005ebc8f5e0eaf177c67640de1108 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 09:29:35 +0200 Subject: [PATCH 1867/3720] MinGW: Skip test redirecting to fd 4 ... because that does not work in MinGW. Signed-off-by: Johannes Schindelin --- t/t0081-line-buffer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index 5067d1e15b..c0031baee0 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -131,7 +131,7 @@ test_expect_success PIPE,EXPENSIVE 'longer read (around 65536 bytes)' ' long_read_test 65536 ' -test_expect_success 'read from file descriptor' ' +test_expect_success NOT_MINGW 'read from file descriptor' ' rm -f input && echo hello >expect && echo hello >input && From c6037ca4decbf641c845333210d506ec90597201 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 16:44:45 +0200 Subject: [PATCH 1868/3720] Disable test on MinGW that challenges its bash quoting Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 4e69c907d8..a65e1a30ea 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -893,7 +893,10 @@ test_expect_success 'remote set-url --add bbb' ' ' test_expect_success 'remote set-url --delete .*' ' - test_must_fail git remote set-url --delete someremote .\* && + if test_have_prereq NOT_MINGW + then + test_must_fail git remote set-url --delete someremote .\* + fi && echo "YYY" >expect && echo baz >>expect && echo bbb >>expect && From dc978147d87a6545d592027ca0dbd0f5b560e32b Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1869/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 62eccd3391..8d768ce3d6 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From 7c8b278d81e0420ebbc9ec21fea3cc2f12f5807d Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1870/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 480dd0a861..8595205ab2 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index ba13a54793..4226c6e782 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 5b896d9845..2c838f94fc 100644 --- a/cache.h +++ b/cache.h @@ -579,6 +579,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 4423961768..c4229d9266 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 8d768ce3d6..06f4d3e0cc 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -309,6 +306,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 5f9ec28945..52c72f97fa 100644 --- a/config.c +++ b/config.c @@ -664,6 +664,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 40185bc854..901d5501d6 100644 --- a/environment.c +++ b/environment.c @@ -57,6 +57,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index e0bb81ed8d..b3e6824fc2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -569,4 +569,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From d86266d546cb99e3a5a9b71cc148a574ee35e3f0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1871/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index c4229d9266..751ed8253a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From e10ee9ea4364b4c612241afeca93006ea32c715b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1872/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From fdb2e9f2cf61b5cfc6df28edb702236a5ed4b144 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1873/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index fd6a43d0a2..3c6dab147e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,9 +1269,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2079,7 +2076,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2091,12 +2088,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2117,18 +2121,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2149,20 +2150,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 9c4e0be61f62d24673bd0e46e663c4999c5f395d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1874/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 3c6dab147e..c5037685e3 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From f13b3a804887df06093a5f61a15dcce897004c24 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1875/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 4cde0c493b..6b18e34726 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9480,7 +9480,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 7bdd17d3d099614246614da4a1f6024345ae0d5c Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1876/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 8106af8fba..7cec9fec92 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' ! test -d newdir/here ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 107e8b41c7587029738b183bdf65a3c49d8949fa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1877/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 7d7fde057b..adb225dc0e 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,6 +228,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index cd6e2c5e87..8a8e2cbcc9 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -719,6 +719,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_i18ncmp expect output ' @@ -735,6 +739,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -761,8 +769,16 @@ test_expect_success 'status submodule summary (clean submodule): commit' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_i18ncmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_i18ncmp expect output ' @@ -777,6 +793,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -812,6 +832,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_i18ncmp expect output ' From ef0e50e0644f19d70bf37ad9eac05df1d68b3329 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1878/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 8595205ab2..a90b1bce3f 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1599,6 +1599,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e1ba4dc697..e2210f9900 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -79,7 +81,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 99bae50ab10e576ec709f3d5ba400a4bd3e8fb7f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1879/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..eadbcaf398 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 3539d6e957423dcb5c3b3cf2d52f0a53e44f545c Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1880/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index eadbcaf398..774f97b8c8 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From fdf3b3f8a417af413b7707a0493d06a6aadccd46 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1881/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 3e3c528497..5ae76049f7 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 751ed8253a..cf74e8948c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1797,3 +1797,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index 06f4d3e0cc..1f754aed3b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -340,3 +340,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 52c72f97fa..097bfa8cfd 100644 --- a/config.c +++ b/config.c @@ -876,7 +876,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index b3e6824fc2..927deb0bf2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -573,4 +573,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 4d73cc9cd2..39b576c298 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 4c50dd6d1bfa29380e4c5da5e3856725ec1fba48 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1882/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From cc297b61c28f171b8bd688d28f65c45a922a7f85 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1883/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 6cdd5910db..b312da10d8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -513,7 +513,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -682,7 +683,8 @@ do case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -755,7 +757,7 @@ do # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" echo "If there is nothing left to stage, chances are that something else" echo "already introduced the same changes; you might want to skip this patch." @@ -779,7 +781,8 @@ do then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say No changes -- Patch already applied. go_next continue From 12ac16c63fd02c389b6b3f156e3108dff7a56ae6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1884/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 763b9c55a8..49c89d7953 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From dba7984b59e68448d07fb41fda14c4b17ab9258e Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1885/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 2c838f94fc..e925bb424c 100644 --- a/cache.h +++ b/cache.h @@ -751,7 +751,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(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 *); diff --git a/compat/mingw.c b/compat/mingw.c index cf74e8948c..4b4b958fb5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1815,3 +1815,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 1f754aed3b..a37b2718d5 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -300,6 +300,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 927deb0bf2..1dda551350 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -211,6 +211,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 39b576c298..8745aad206 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 6df8bcd8abf97d035167d33d745d4833c9888eaa Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1886/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 5ae76049f7..9bf63d8c8a 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 504c26dab5efb597265b7bc0bc04f96d904e4cfa Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1887/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b4b958fb5..688c7f3a8f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1818,23 +1818,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From b9d339eee85a222c841559edb378f744cc37e1c6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1888/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index c5037685e3..0d5bd3465f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 364a83ca51207804e34b381c88b0ae02189032ca Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1889/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 6b18e34726..2a92e20f06 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9480,18 +9480,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9502,6 +9491,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 5860fad896e8b2846ebcb73a08aa2510ed9af4f2 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1890/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 688c7f3a8f..e82a3bd123 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -668,11 +668,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From c2ba388343bfb9039f4dd05053a9ba35f255bb49 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1891/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index a37b2718d5..9155ce3af2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 95dc6b770de10b78e029628e4e27fed1e635ebd7 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1892/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From de6df2fe4eca8f26f77c1d897fbec5fea60cc4ab Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1893/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From f403f7162c5cfe3ade4750187021531e56d78126 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1894/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index 2a1e3a94c9..59133640f4 100644 --- a/log-tree.c +++ b/log-tree.c @@ -506,7 +506,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 3f2dc6bd6746a54cc5c6d065ede5f3934de2bfb5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1895/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ee69ea683a..dc3cb8e9a5 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4026,6 +4026,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 63d6dc69100041ff2abe774977e8f325df171958 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1896/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index dc3cb8e9a5..4049ccd973 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4041,7 +4041,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 36e409787c11028fb673083d50393698a7e465c1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1897/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 9e767723ed..649e26fd6e 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 2b04d7695e1e071bc97e8de63b30224a56f27862 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1898/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index d39a6ab930..9324b4ddc9 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -278,6 +278,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die (_("Could not open '%s' for writing."), file); From d73c3c04cf4e9ded10dfd954ab151e733defe196 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1899/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e2210f9900..2374ebea60 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -339,7 +339,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 0b23a07e0e4a406ee805258b1d622321facd3db0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1900/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 3ee2ec51de..9a4e42b9c0 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -178,6 +179,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -188,6 +205,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -505,6 +525,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -920,6 +943,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); From 8d467d22e34cc7272d454466f9e3cd4d95729f3f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1901/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3a1fe20ff2..ad7630bed2 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 33a58a45b65b4358c270c9bcfe94fc6e51031f72 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1902/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e82a3bd123..bb4bfb2084 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1803,7 +1803,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From b7f3e11c59058b70fc413a1880e5934812ae83fb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1903/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ad7630bed2..dec4a7f38a 100644 --- a/Makefile +++ b/Makefile @@ -1886,7 +1886,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1926,6 +1926,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From afd3a2cc41f20840205f02c74d69f6e42452c2e8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1904/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index da6252b117..4b7236abcf 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -340,6 +340,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From 07e4ec128d3d6566cf944c6d7a5ee92d37b34cb5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 1905/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 9a4e42b9c0..c9121b2249 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1015,6 +1015,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From e51d5af4efa828f5fadd1fecfda642247a1bb0d8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 1906/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index c9121b2249..a5b620c60b 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1015,7 +1015,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From c3e2378010f474f96aaa2d4ee2e8b09d5447a69e Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 1907/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From fbe9dcfa95207702e060423a2308584ab340ce72 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1908/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index bb4bfb2084..6b3a8cf699 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 771776072219de19b8dc3002d50f6ee69698d021 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 09:29:35 +0200 Subject: [PATCH 1909/3720] MinGW: Skip test redirecting to fd 4 ... because that does not work in MinGW. Signed-off-by: Johannes Schindelin --- t/t0081-line-buffer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index 5067d1e15b..c0031baee0 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -131,7 +131,7 @@ test_expect_success PIPE,EXPENSIVE 'longer read (around 65536 bytes)' ' long_read_test 65536 ' -test_expect_success 'read from file descriptor' ' +test_expect_success NOT_MINGW 'read from file descriptor' ' rm -f input && echo hello >expect && echo hello >input && From 53ea416bd3f5ea25c0f7997a14f4a7ac45cfe27c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 16:44:45 +0200 Subject: [PATCH 1910/3720] Disable test on MinGW that challenges its bash quoting Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 4e69c907d8..a65e1a30ea 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -893,7 +893,10 @@ test_expect_success 'remote set-url --add bbb' ' ' test_expect_success 'remote set-url --delete .*' ' - test_must_fail git remote set-url --delete someremote .\* && + if test_have_prereq NOT_MINGW + then + test_must_fail git remote set-url --delete someremote .\* + fi && echo "YYY" >expect && echo baz >>expect && echo bbb >>expect && From 107dbe59d95d05fa8d4884786fb4d9feb24aed63 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Tue, 26 Apr 2011 10:39:30 +0100 Subject: [PATCH 1911/3720] t3102: Windows filesystems may not use a literal asterisk in filenames. Exclude these tests when using MINGW. Signed-off-by: Pat Thoyts --- t/t3102-ls-tree-wildcards.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh index f2b2a524d9..44a32edd28 100755 --- a/t/t3102-ls-tree-wildcards.sh +++ b/t/t3102-ls-tree-wildcards.sh @@ -4,14 +4,14 @@ test_description='ls-tree with(out) wildcards' . ./test-lib.sh -test_expect_success 'setup' ' +test_expect_success NOT_MINGW 'setup' ' mkdir a aa "a*" && touch a/one aa/two "a*/three" && git add a/one aa/two "a*/three" && git commit -m test ' -test_expect_success 'ls-tree a* matches literally' ' +test_expect_success NOT_MINGW 'ls-tree a* matches literally' ' cat >expected < Date: Wed, 27 Apr 2011 18:38:04 +0200 Subject: [PATCH 1912/3720] submodule: Use cat instead of echo to avoid DOS line-endings, was: Re: 4msysgit & tags In msysGit, echo used in scripts outputs DOS line-endings while built-ins use Unix line-endings in their output. This causes t7508-status to fail due to mixed line endings in the output of git status (which calls git-submodule). Signed-off-by: Sebastian Schuberth --- git-submodule.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index bf110e9cb7..24e6eda31c 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -742,12 +742,16 @@ cmd_summary() { done | if test -n "$for_status"; then if [ -n "$files" ]; then - echo "# Submodules changed but not updated:" + status_msg="# Submodules changed but not updated:" else - echo "# Submodule changes to be committed:" + status_msg="# Submodule changes to be committed:" fi - echo "#" - sed -e 's|^|# |' -e 's|^# $|#|' + status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|') + cat < Date: Thu, 28 Apr 2011 15:29:59 +0200 Subject: [PATCH 1913/3720] submodule: Use cat instead of echo to avoid DOS line-endings From 599f5058a0ef54de51159de1fe9b93e4ef507650 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Sun, 1 May 2011 14:47:09 +0100 Subject: [PATCH 1914/3720] t5407: Fix line-ending dependency in post-rewrite.args On msysGit creating the post-rewrite.args file using 'echo' has different line endings from the expected comparison. Using perl normalizes the line endings for each generated file. Signed-off-by: Pat Thoyts --- t/t5407-post-rewrite-hook.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index baa670cea5..35403b435e 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -20,9 +20,13 @@ test_expect_success 'setup' ' mkdir .git/hooks cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args -cat > "$TRASH_DIRECTORY"/post-rewrite.data +#!/usr/bin/perl +open (AR, ">$TRASH_DIRECTORY/post-rewrite.args"); +print AR \$_,"\n" foreach @ARGV; +open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data"); +while() { + print DAT; +} EOF chmod u+x .git/hooks/post-rewrite From f33946d98dc868f188381e71d5601f79bad7195b Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Thu, 28 Apr 2011 00:30:49 +0200 Subject: [PATCH 1915/3720] submodule: Fix t7400, t7405, t7406 for msysGit Again, avoid using echo (which issues DOS line endings on msysGit) to not mix with Unix line-endings issued by git built-ins, even if this is at the cost of calling an external executable (cat) instead of a shell built-in (echo). --- git-sh-setup.sh | 4 +++- git-submodule.sh | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index aa16b83565..2814578de1 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -49,7 +49,9 @@ GIT_QUIET= say () { if test -z "$GIT_QUIET" then - printf '%s\n' "$*" + cat < /dev/null 2>&1 then - echo >&2 "The following path is ignored by one of your .gitignore files:" && - echo >&2 $path && - echo >&2 "Use -f if you really want to add it." + cat >&2 < Date: Thu, 28 Apr 2011 00:34:15 +0200 Subject: [PATCH 1916/3720] Partly revert "Work around funny CR issue" This party reverts commit 4dc7d3b9f940463810d66dcddd9ccee7dc8c2e99. A more generic fix is applied to git-submodule.sh in "Fix t7400, t7405, t7406 for msysGit". --- t/t7401-submodule-summary.sh | 4 ---- t/t7508-status.sh | 24 ------------------------ 2 files changed, 28 deletions(-) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index adb225dc0e..7d7fde057b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -228,10 +228,6 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && - if test_have_prereq MINGW - then - dos2unix actual - fi && test_cmp actual - <output && - if test_have_prereq MINGW - then - dos2unix output - fi && test_i18ncmp expect output ' @@ -739,10 +735,6 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && - if test_have_prereq MINGW - then - dos2unix output - fi && test_cmp expect output ' @@ -769,16 +761,8 @@ test_expect_success 'status submodule summary (clean submodule): commit' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && - if test_have_prereq MINGW - then - dos2unix output - fi && test_i18ncmp expect output && git status >output && - if test_have_prereq MINGW - then - dos2unix output - fi && test_i18ncmp expect output ' @@ -793,10 +777,6 @@ cat >expect <output && - if test_have_prereq MINGW - then - dos2unix output - fi && test_cmp expect output ' @@ -832,10 +812,6 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && - if test_have_prereq MINGW - then - dos2unix output - fi && test_i18ncmp expect output ' From 1ea860106faf11529261a3fc92d87f5f6ac90608 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1917/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 547568b918..a06c42396d 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From e432f3eff319996e32be8cdbaad5a6b7cf2840b0 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1918/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 6b93777199..c74d4f9585 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 025aa47c80..c1098bc029 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 48bddf2dd8..16f7483e32 100644 --- a/cache.h +++ b/cache.h @@ -582,6 +582,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f6e9ff7762..2221db8071 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index a06c42396d..a274e2b546 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -312,6 +309,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index a8267e9265..06d99d652c 100644 --- a/config.c +++ b/config.c @@ -652,6 +652,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 94d58fd244..8eed47aeb3 100644 --- a/environment.c +++ b/environment.c @@ -57,6 +57,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index e0bb81ed8d..b3e6824fc2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -569,4 +569,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 91a5fb50a6c35ed5939d140ef11811d82ff3a714 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1919/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 2221db8071..4aebb3d24f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 350234de5722cbb9e18d4ca851f96b66acb1258e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1920/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From bb23eee264536e0d80e7988c581ee2cba0c21829 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1921/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index fd6a43d0a2..3c6dab147e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,9 +1269,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2079,7 +2076,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2091,12 +2088,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2117,18 +2121,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2149,20 +2150,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 8fe3e3b15aa47e1d32cf84d318eb5b8d214a3bde Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1922/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 3c6dab147e..c5037685e3 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 94fed4c7f814dfeb413b7fb5da74b07255fce6fd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1923/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 4cde0c493b..6b18e34726 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9480,7 +9480,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From ce0fbc61c19eb18acb3cee63e56b51ed1a924d44 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1924/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index ad66410564..b157cb8581 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' ! test -d newdir/here ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From c96279854e8fc45214ccfd105224f6ca3e1c19c6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1925/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7407-submodule-foreach.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index ae3bd18a5e..761337ebd9 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -176,6 +176,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +227,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' From 4a5083848cc7755051dcc6f915b044e2ca264b5d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1926/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c74d4f9585..53e24a5bf1 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1619,6 +1619,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e1a687ad07..2ea4c2bbfe 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -18,7 +18,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -80,7 +82,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -330,6 +337,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -356,6 +401,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -384,6 +436,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 332a8969697e9cdca527e9fbaf65c0581624e1b7 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1927/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 98ab33aae7..f53d2ef429 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 89054d14572e86622ed7f080d68cd8e138071cd2 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1928/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index f53d2ef429..66f7abd6ed 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From fe6643e1f41837a1f15680c56a424e6a9466167d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1929/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 211e118d57..4ac4d17f4b 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 4aebb3d24f..1f4012f638 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1804,3 +1804,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index a274e2b546..89ab26187a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -343,3 +343,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 06d99d652c..e286a62ae0 100644 --- a/config.c +++ b/config.c @@ -853,7 +853,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index b3e6824fc2..927deb0bf2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -573,4 +573,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 4d73cc9cd2..39b576c298 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From 79a382f031c857b0c79f2887a42a3b14c2588e90 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1930/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From a9415460d4cdcb3f0fb9ce8b6d4be1431867a659 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1931/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 463c741dfc..038446d7a8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -517,7 +517,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -686,7 +687,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -762,7 +764,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { gettext "No changes - did you forget to use 'git add'? If there is nothing left to stage, chances are that something else already introduced the same changes; you might want to skip this patch."; echo @@ -786,7 +788,8 @@ did you forget to use 'git add'?"; echo then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say "$(gettext "No changes -- Patch already applied.")" go_next continue From c6e7d36df36d293b7a5471288c599dcbed568172 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1932/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 64390d716d..cc3ebefb43 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 201d6b8c03700331c69ac148c5cae33e8c7a6929 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1933/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 16f7483e32..e23f53c015 100644 --- a/cache.h +++ b/cache.h @@ -764,7 +764,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(const char *path); /* object replacement */ #define READ_SHA1_FILE_REPLACE 1 diff --git a/compat/mingw.c b/compat/mingw.c index 1f4012f638..d319e493b5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1822,3 +1822,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 89ab26187a..d5f95ef662 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -303,6 +303,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 927deb0bf2..1dda551350 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -211,6 +211,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 39b576c298..8745aad206 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 63c8cbf8478fad65c7bda7c923f141589d86f3b0 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1934/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 4ac4d17f4b..9ac3b9ec69 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From e864f136e947c9430e3c257befb19cb08b542d94 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1935/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d319e493b5..5bf6982e4e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1825,23 +1825,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 6a52c8ae13ad4469673799885ff9b05400ebc082 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1936/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index c5037685e3..0d5bd3465f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 7eb90ceb38068443654b67a5c9fe11fbcd528215 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1937/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 6b18e34726..2a92e20f06 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9480,18 +9480,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9502,6 +9491,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 4b222bd3a4d9428af0052e353bdf5adab235ee92 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1938/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5bf6982e4e..8f3f64c33c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -668,11 +668,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 3bc1bcd68d940a726395b59bffeb7a93c094b9d3 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1939/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index d5f95ef662..9abbec6190 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -293,9 +293,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 57d7fef28fb0c07caac28eec703a22eac6e969ef Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1940/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 16df0e9a822fbd31596661740b8d8b108f0f3ecc Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1941/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From a75ae02b3be150bdb95adbed453bcf00740ad22c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1942/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index 2a1e3a94c9..59133640f4 100644 --- a/log-tree.c +++ b/log-tree.c @@ -506,7 +506,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From aa3c95085db6256e289f6f370150112b379ea32c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1943/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 240dd4701c..e1ae8f9773 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4216,6 +4216,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From a3dc804b857aebe09cf1025bbce9c12e06d45f17 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1944/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e1ae8f9773..4b499743ee 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4231,7 +4231,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 8a440e7ea1d4dcc2046707a386e73c5c9b528ea9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1945/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index b2ae8de16d..e9c6d22809 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From a6134f86825679b50e651d114a5592d9d726ae40 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1946/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index c59b0c98fe..68fd050e94 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die (_("Could not open '%s' for writing."), file); From 9e678b6d78bdd2bee1aaaa5cb79706752d0c4692 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1947/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 2ea4c2bbfe..a638ecd815 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -340,7 +340,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 6e9ce2238b201ec811cf2f747a9d0d0d3d47ffe5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1948/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 871afaa3c7..6ef443ec4f 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -178,6 +179,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -188,6 +205,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -505,6 +525,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -956,6 +979,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); From c3181a3640645d2b290399239b3bb9de4646be00 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1949/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f8c72e10a0..308bd2c3f9 100644 --- a/Makefile +++ b/Makefile @@ -271,7 +271,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 18079fb35282ea3a53a22c7b69bb8250bb792b18 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1950/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8f3f64c33c..a2b1a587e6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1810,7 +1810,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From e33a58a4f96ce3d0d1df957492c38ff0842e4058 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1951/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 308bd2c3f9..b2e1759219 100644 --- a/Makefile +++ b/Makefile @@ -1886,7 +1886,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1926,6 +1926,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From f558bb1780cb033216e8a1a8270804695190aeaf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1952/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index 63849836c8..2ef2ec912e 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From 0e4d0355783ba9fcf5bd3de33748e2313ddb8a3c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 1953/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 6ef443ec4f..a953289e90 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1043,6 +1043,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From 5473487bbe567a190244b9456d0abc4c0187e3b4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 1954/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index a953289e90..e7c1c9f0d1 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1043,7 +1043,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From 46f513faa0e5a991644b646d473c33c95d4d5d81 Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 1955/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From bed1e5f23bde1fda1560612c157e1385a3414453 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 1956/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index a2b1a587e6..17d213dc4c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 9d277a097236efe1d99c13c41ed6bf284d35632a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 09:29:35 +0200 Subject: [PATCH 1957/3720] MinGW: Skip test redirecting to fd 4 ... because that does not work in MinGW. Signed-off-by: Johannes Schindelin --- t/t0081-line-buffer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index bd83ed371a..25dba008f3 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' ' test_cmp expect actual ' -test_expect_success 'read from file descriptor' ' +test_expect_success NOT_MINGW 'read from file descriptor' ' rm -f input && echo hello >expect && echo hello >input && From ecee00a5b457502795a04fe2b567b921ba6adab7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 16:44:45 +0200 Subject: [PATCH 1958/3720] Disable test on MinGW that challenges its bash quoting Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 4e69c907d8..a65e1a30ea 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -893,7 +893,10 @@ test_expect_success 'remote set-url --add bbb' ' ' test_expect_success 'remote set-url --delete .*' ' - test_must_fail git remote set-url --delete someremote .\* && + if test_have_prereq NOT_MINGW + then + test_must_fail git remote set-url --delete someremote .\* + fi && echo "YYY" >expect && echo baz >>expect && echo bbb >>expect && From e0698c6e304fd490a9f6432c283a1c1c257b3e8f Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Tue, 26 Apr 2011 10:39:30 +0100 Subject: [PATCH 1959/3720] t3102: Windows filesystems may not use a literal asterisk in filenames. Exclude these tests when using MINGW. Signed-off-by: Pat Thoyts --- t/t3102-ls-tree-wildcards.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh index c286854485..766af3de9b 100755 --- a/t/t3102-ls-tree-wildcards.sh +++ b/t/t3102-ls-tree-wildcards.sh @@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs' . ./test-lib.sh -test_expect_success 'setup' ' +test_expect_success NOT_MINGW 'setup' ' mkdir a aa "a[a]" && touch a/one aa/two "a[a]/three" && git add a/one aa/two "a[a]/three" && git commit -m test ' -test_expect_success 'ls-tree a[a] matches literally' ' +test_expect_success NOT_MINGW 'ls-tree a* matches literally' ' cat >expected < Date: Wed, 27 Apr 2011 18:38:04 +0200 Subject: [PATCH 1960/3720] submodule: Use cat instead of echo to avoid DOS line-endings In msysGit, echo used in scripts outputs DOS line-endings while built-ins use Unix line-endings in their output. This causes t7508-status to fail due to mixed line endings in the output of git status (which calls git-submodule). Signed-off-by: Sebastian Schuberth --- git-submodule.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index c1d3a5e2fa..c1e89edd85 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -750,12 +750,16 @@ cmd_summary() { done | if test -n "$for_status"; then if [ -n "$files" ]; then - gettext "# Submodules changed but not updated:"; echo + status_msg="$(gettext "# Submodules changed but not updated:")" else - gettext "# Submodule changes to be committed:"; echo + status_msg="$(gettext "# Submodule changes to be committed:")" fi - echo "#" - sed -e 's|^|# |' -e 's|^# $|#|' + status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|') + cat < Date: Sun, 1 May 2011 14:47:09 +0100 Subject: [PATCH 1961/3720] t5407: Fix line-ending dependency in post-rewrite.args On msysGit creating the post-rewrite.args file using 'echo' has different line endings from the expected comparison. Using perl normalizes the line endings for each generated file. Signed-off-by: Pat Thoyts --- t/t5407-post-rewrite-hook.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index baa670cea5..35403b435e 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -20,9 +20,13 @@ test_expect_success 'setup' ' mkdir .git/hooks cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args -cat > "$TRASH_DIRECTORY"/post-rewrite.data +#!/usr/bin/perl +open (AR, ">$TRASH_DIRECTORY/post-rewrite.args"); +print AR \$_,"\n" foreach @ARGV; +open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data"); +while() { + print DAT; +} EOF chmod u+x .git/hooks/post-rewrite From b92ffe1e7459b4010a3153c571802a11333aeaa5 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Thu, 28 Apr 2011 00:30:49 +0200 Subject: [PATCH 1962/3720] submodule: Fix t7400, t7405, t7406 for msysGit Again, avoid using echo (which issues DOS line endings on msysGit) to not mix with Unix line-endings issued by git built-ins, even if this is at the cost of calling an external executable (cat) instead of a shell built-in (echo). --- git-sh-setup.sh | 4 +++- git-submodule.sh | 11 +++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 94e26ed5e8..e3ad57a7e4 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -49,7 +49,9 @@ GIT_QUIET= say () { if test -z "$GIT_QUIET" then - printf '%s\n' "$*" + cat < /dev/null 2>&1 then - ( - eval_gettext "The following path is ignored by one of your .gitignore files: -\$path -Use -f if you really want to add it." && - echo - ) >&2 + cat >&2 < Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 1963/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 547568b918..a06c42396d 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From 7f6b2c3063710a781bb8f94a5995f506e9d33fc8 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 1964/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 6b93777199..c74d4f9585 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 025aa47c80..c1098bc029 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 48bddf2dd8..16f7483e32 100644 --- a/cache.h +++ b/cache.h @@ -582,6 +582,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f6e9ff7762..2221db8071 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index a06c42396d..a274e2b546 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -312,6 +309,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index e0b3b80d92..8a68cb16fd 100644 --- a/config.c +++ b/config.c @@ -652,6 +652,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 94d58fd244..8eed47aeb3 100644 --- a/environment.c +++ b/environment.c @@ -57,6 +57,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index e0bb81ed8d..b3e6824fc2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -569,4 +569,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From f0aea78245e0c6ccfaebb1460d5794663f0cd419 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 1965/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 2221db8071..4aebb3d24f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 043069eea365c4347fb52e9cbf4c307f854d6e3b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 1966/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 17ae962f0dc09439049341fc2f07a16f3ad9f9c8 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 1967/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index fd6a43d0a2..3c6dab147e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,9 +1269,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2079,7 +2076,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2091,12 +2088,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2117,18 +2121,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2149,20 +2150,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 7b6b6e07a1dfd87c163bba300e6e7bc492d45e0f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 1968/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 3c6dab147e..c5037685e3 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From a639d8ec84e6c77f4a08a81314594ed5322a9d7a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 1969/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 4cde0c493b..6b18e34726 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9480,7 +9480,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 59a6eab805547f76846acc351bc5236831d2732d Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 1970/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index ad66410564..b157cb8581 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' ! test -d newdir/here ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From caa89b065712edcc3eaf1fc0ce3fea58f9c628a0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 1971/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7407-submodule-foreach.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index ae3bd18a5e..761337ebd9 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -176,6 +176,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +227,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' From bb43a972b7f6adc4fe5e0842489151a8283a8ba1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 1972/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c74d4f9585..53e24a5bf1 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1619,6 +1619,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e1a687ad07..2ea4c2bbfe 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -18,7 +18,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -80,7 +82,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -330,6 +337,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -356,6 +401,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -384,6 +436,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 5e8aef6505e4fb420ce4565bbc748dfe36c5a42c Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 1973/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 98ab33aae7..f53d2ef429 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 0237c52566eb4ddf4bc6a480313fae2631d8426a Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 1974/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index f53d2ef429..66f7abd6ed 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From e869db12c53698321477acb4a6ca3668f9ed6197 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 1975/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 211e118d57..4ac4d17f4b 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 4aebb3d24f..1f4012f638 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1804,3 +1804,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index a274e2b546..89ab26187a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -343,3 +343,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 8a68cb16fd..6a3b3f18d4 100644 --- a/config.c +++ b/config.c @@ -848,7 +848,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index b3e6824fc2..927deb0bf2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -573,4 +573,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 4d73cc9cd2..39b576c298 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From dfeaac71c516e550448a504cbe69b4339e64533f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 1976/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From e1d02997cdb680be5f94ab45758280f2a81cb097 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 1977/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 463c741dfc..038446d7a8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -517,7 +517,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -686,7 +687,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -762,7 +764,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { gettext "No changes - did you forget to use 'git add'? If there is nothing left to stage, chances are that something else already introduced the same changes; you might want to skip this patch."; echo @@ -786,7 +788,8 @@ did you forget to use 'git add'?"; echo then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say "$(gettext "No changes -- Patch already applied.")" go_next continue From 6ca341d4aadd62ae6221a22e69b32656232a9bfd Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 1978/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 64390d716d..cc3ebefb43 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From f2c18f7da52cb6b4b30bc5bf848a597d999ebf61 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 1979/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 16f7483e32..e23f53c015 100644 --- a/cache.h +++ b/cache.h @@ -764,7 +764,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(const char *path); /* object replacement */ #define READ_SHA1_FILE_REPLACE 1 diff --git a/compat/mingw.c b/compat/mingw.c index 1f4012f638..d319e493b5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1822,3 +1822,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 89ab26187a..d5f95ef662 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -303,6 +303,8 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 927deb0bf2..1dda551350 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -211,6 +211,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 39b576c298..8745aad206 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 482a545c4ad43df4c84ff32ffea62fbfeaf1806e Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 1980/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 4ac4d17f4b..9ac3b9ec69 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From facd7b406008a22caa4d505a6a0e39d6dc6a8bb0 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 1981/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d319e493b5..5bf6982e4e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1825,23 +1825,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From d3b5be2849ce147643a4b9301c096b85cae69af1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 1982/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index c5037685e3..0d5bd3465f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 38664054678e7e1e2f81edd6413327c60207dcc3 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 1983/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 6b18e34726..2a92e20f06 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9480,18 +9480,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9502,6 +9491,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From fb8f4aeabd829fbca39be3af63444aabdd865424 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 1984/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5bf6982e4e..8f3f64c33c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -668,11 +668,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From 0dbe6046f220dc7d5466a737ce6bef0ccb69c7bb Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 1985/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index d5f95ef662..9abbec6190 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -293,9 +293,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From e274f1b854781e41b858218e87443f5d270ee74d Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 1986/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 44cb8a5015b50b598809f9455d8c9e48c2c0e464 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 1987/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From 43684c69ce0627493987d1358d3c067a3b1a0299 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 1988/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index e9457019d5..c0afd976d9 100644 --- a/log-tree.c +++ b/log-tree.c @@ -509,7 +509,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 2d1c533b88379dc1592a8b87b82b8c26d8844c12 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 1989/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 240dd4701c..e1ae8f9773 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4216,6 +4216,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From ef0256f4f2b7d8a481c94362f24b9d6fb4b30391 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 1990/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e1ae8f9773..4b499743ee 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4231,7 +4231,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 86beb214f1f9520423b0b43c086ed76f2c93142a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 1991/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index b2ae8de16d..e9c6d22809 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From fba766b9d5a365d40d5f4436f021ec7ef2876475 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 1992/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index c59b0c98fe..68fd050e94 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die (_("Could not open '%s' for writing."), file); From 55cc8dad88fac51e5dcf0f8f9f9a94817575a4c9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 1993/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 2ea4c2bbfe..a638ecd815 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -340,7 +340,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From 825bcda80aec23d7f076de59570294483ba0a2ac Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 1994/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 871afaa3c7..6ef443ec4f 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -178,6 +179,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -188,6 +205,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -505,6 +525,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -956,6 +979,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); From 99f493f529c9a6ac250d5cc514ec43209e83f0ec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 1995/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f8c72e10a0..308bd2c3f9 100644 --- a/Makefile +++ b/Makefile @@ -271,7 +271,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 41d4e2e599d6f73b8cef3e50e7fd1127b55fba88 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 1996/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8f3f64c33c..a2b1a587e6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1810,7 +1810,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From d9f22a2ad014f58a3d967f977bcbca46179baab2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 1997/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 308bd2c3f9..b2e1759219 100644 --- a/Makefile +++ b/Makefile @@ -1886,7 +1886,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1926,6 +1926,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From 4b66d0080649ba394af0b147cd2cdc7eab92a152 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 1998/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index 63849836c8..2ef2ec912e 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From 6ed080739210b7eb4cc375546ce61b65ab7c0d22 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 1999/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 6ef443ec4f..a953289e90 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1043,6 +1043,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From 4c27350706503de83b3128d1d4120a2968758854 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 2000/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index a953289e90..e7c1c9f0d1 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1043,7 +1043,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From 9b3eb676291dfb020b233957ee161a3f73697940 Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 2001/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From 9a5be1b93bcd95899134503a7079ba13d666d6ab Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 2002/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index a2b1a587e6..17d213dc4c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 3729ca7f2fb38b2cb660fe52695e9198034e9ae4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 09:29:35 +0200 Subject: [PATCH 2003/3720] MinGW: Skip test redirecting to fd 4 ... because that does not work in MinGW. Signed-off-by: Johannes Schindelin --- t/t0081-line-buffer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index bd83ed371a..25dba008f3 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' ' test_cmp expect actual ' -test_expect_success 'read from file descriptor' ' +test_expect_success NOT_MINGW 'read from file descriptor' ' rm -f input && echo hello >expect && echo hello >input && From be8b0d081a8d6012126323c58cdac460b02dbd1d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 16:44:45 +0200 Subject: [PATCH 2004/3720] Disable test on MinGW that challenges its bash quoting Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0d0222ea2a..fae1200255 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -915,7 +915,10 @@ test_expect_success 'remote set-url --add bbb' ' ' test_expect_success 'remote set-url --delete .*' ' - test_must_fail git remote set-url --delete someremote .\* && + if test_have_prereq NOT_MINGW + then + test_must_fail git remote set-url --delete someremote .\* + fi && echo "YYY" >expect && echo baz >>expect && echo bbb >>expect && From a3cea538dbb66f0a71d0b7e40c991bb44f73e4c9 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Tue, 26 Apr 2011 10:39:30 +0100 Subject: [PATCH 2005/3720] t3102: Windows filesystems may not use a literal asterisk in filenames. Exclude these tests when using MINGW. Signed-off-by: Pat Thoyts --- t/t3102-ls-tree-wildcards.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh index c286854485..766af3de9b 100755 --- a/t/t3102-ls-tree-wildcards.sh +++ b/t/t3102-ls-tree-wildcards.sh @@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs' . ./test-lib.sh -test_expect_success 'setup' ' +test_expect_success NOT_MINGW 'setup' ' mkdir a aa "a[a]" && touch a/one aa/two "a[a]/three" && git add a/one aa/two "a[a]/three" && git commit -m test ' -test_expect_success 'ls-tree a[a] matches literally' ' +test_expect_success NOT_MINGW 'ls-tree a* matches literally' ' cat >expected < Date: Wed, 27 Apr 2011 18:38:04 +0200 Subject: [PATCH 2006/3720] submodule: Use cat instead of echo to avoid DOS line-endings In msysGit, echo used in scripts outputs DOS line-endings while built-ins use Unix line-endings in their output. This causes t7508-status to fail due to mixed line endings in the output of git status (which calls git-submodule). Signed-off-by: Sebastian Schuberth --- git-submodule.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index c571d320d0..1bf19b733c 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -750,12 +750,16 @@ cmd_summary() { done | if test -n "$for_status"; then if [ -n "$files" ]; then - gettext "# Submodules changed but not updated:"; echo + status_msg="$(gettext "# Submodules changed but not updated:")" else - gettext "# Submodule changes to be committed:"; echo + status_msg="$(gettext "# Submodule changes to be committed:")" fi - echo "#" - sed -e 's|^|# |' -e 's|^# $|#|' + status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|') + cat < Date: Sun, 1 May 2011 14:47:09 +0100 Subject: [PATCH 2007/3720] t5407: Fix line-ending dependency in post-rewrite.args On msysGit creating the post-rewrite.args file using 'echo' has different line endings from the expected comparison. Using perl normalizes the line endings for each generated file. Signed-off-by: Pat Thoyts --- t/t5407-post-rewrite-hook.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index baa670cea5..35403b435e 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -20,9 +20,13 @@ test_expect_success 'setup' ' mkdir .git/hooks cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args -cat > "$TRASH_DIRECTORY"/post-rewrite.data +#!/usr/bin/perl +open (AR, ">$TRASH_DIRECTORY/post-rewrite.args"); +print AR \$_,"\n" foreach @ARGV; +open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data"); +while() { + print DAT; +} EOF chmod u+x .git/hooks/post-rewrite From 1d02353412c6e573a143be1ed8160c47a7464c80 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Thu, 28 Apr 2011 00:30:49 +0200 Subject: [PATCH 2008/3720] submodule: Fix t7400, t7405, t7406 for msysGit Again, avoid using echo (which issues DOS line endings on msysGit) to not mix with Unix line-endings issued by git built-ins, even if this is at the cost of calling an external executable (cat) instead of a shell built-in (echo). --- git-sh-setup.sh | 4 +++- git-submodule.sh | 11 +++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 94e26ed5e8..e3ad57a7e4 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -49,7 +49,9 @@ GIT_QUIET= say () { if test -z "$GIT_QUIET" then - printf '%s\n' "$*" + cat < /dev/null 2>&1 then - ( - eval_gettext "The following path is ignored by one of your .gitignore files: -\$path -Use -f if you really want to add it." && - echo - ) >&2 + cat >&2 < Date: Wed, 1 Jun 2011 15:00:39 +0200 Subject: [PATCH 2009/3720] fixup! Work around funny CR issue --- t/t7407-submodule-foreach.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 761337ebd9..72a4fdebd2 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' ' git config foo.bar zar && git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar" ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_i18ncmp expect actual ' @@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_i18ncmp expect actual ' From 5ff1232f6360c596bcaba9aa74991e28ea9b800a Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 2010/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index ce9dd980eb..b659c9f4ef 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From 2ae63aec571e1e1184bc72af0338b1fd91f5111c Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 2011/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 6b93777199..c74d4f9585 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 025aa47c80..c1098bc029 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index 79c9302e22..be33265ee4 100644 --- a/cache.h +++ b/cache.h @@ -582,6 +582,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index f6e9ff7762..2221db8071 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index b659c9f4ef..78ff4c5832 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -321,6 +318,9 @@ static inline char *mingw_find_last_dir_sep(const char *path) void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index e0b3b80d92..8a68cb16fd 100644 --- a/config.c +++ b/config.c @@ -652,6 +652,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 94d58fd244..8eed47aeb3 100644 --- a/environment.c +++ b/environment.c @@ -57,6 +57,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index a75530df7b..c3114cd41d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -573,4 +573,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 8e158b5feeb916a21410e07b0713b75824e143ab Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 2012/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 2221db8071..4aebb3d24f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 47953b3250276a0a431af24214fd4bd6778bdab8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 2013/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 823a82d38e107080dafce09db3f6c0e66571431e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 2014/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index fd6a43d0a2..3c6dab147e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,9 +1269,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2079,7 +2076,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2091,12 +2088,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2117,18 +2121,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2149,20 +2150,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 38abb8a64b995df89e60259a343feaaf7a1e5665 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 2015/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 3c6dab147e..c5037685e3 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 4de5ad8f25bb7c24cd509de19ecd63263f5033a1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 2016/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 4cde0c493b..6b18e34726 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9480,7 +9480,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From fda2f6a05202c1b0179bd831ca7be3a386fbd1f0 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 2017/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index ad66410564..b157cb8581 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' ! test -d newdir/here ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From e40a69ca513deda00e88db0b60652b5c0e74a055 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 2018/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index ae3bd18a5e..72a4fdebd2 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' ' git config foo.bar zar && git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar" ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_i18ncmp expect actual ' @@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_i18ncmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' From 4d7ce0fe2dbf06f28bcff793fbd261644d6b02d8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 2019/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c74d4f9585..53e24a5bf1 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1619,6 +1619,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e1a687ad07..2ea4c2bbfe 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -18,7 +18,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -80,7 +82,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -330,6 +337,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -356,6 +401,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -384,6 +436,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d73731e644..eb6fce848f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 7f96f7bb51628502af5af3719db0827e793bd2c5 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 2020/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 98ab33aae7..f53d2ef429 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 7f85784034a7eee03c209a90fa59752f3eabbfe0 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 2021/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index f53d2ef429..66f7abd6ed 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From 1a284c935fc8f0a0a14142f0f3939c433f121eab Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 2022/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 211e118d57..4ac4d17f4b 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index 4aebb3d24f..1f4012f638 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1804,3 +1804,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index 78ff4c5832..3078f39678 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -352,3 +352,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 8a68cb16fd..6a3b3f18d4 100644 --- a/config.c +++ b/config.c @@ -848,7 +848,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index c3114cd41d..6053871bc3 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -577,4 +577,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 4d73cc9cd2..39b576c298 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From b5a1c75130866fae7154ad2db6abeb949ce2b7c0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 2023/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From 5f268c784a7f4979bda85a07da8e46c20a77d5b6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 2024/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 463c741dfc..038446d7a8 100755 --- a/git-am.sh +++ b/git-am.sh @@ -517,7 +517,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -686,7 +687,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -762,7 +764,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { gettext "No changes - did you forget to use 'git add'? If there is nothing left to stage, chances are that something else already introduced the same changes; you might want to skip this patch."; echo @@ -786,7 +788,8 @@ did you forget to use 'git add'?"; echo then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say "$(gettext "No changes -- Patch already applied.")" go_next continue From b33b6e0e3e61e6a5bb676e2bc59129c212b49fee Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 2025/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 64390d716d..cc3ebefb43 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From de7b43657811c5508a31a0b7497244ce8076d600 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 2026/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index be33265ee4..5095e7c377 100644 --- a/cache.h +++ b/cache.h @@ -764,7 +764,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(const char *path); /* object replacement */ #define READ_SHA1_FILE_REPLACE 1 diff --git a/compat/mingw.c b/compat/mingw.c index 1f4012f638..d319e493b5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1822,3 +1822,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 3078f39678..ee3104b6a9 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -312,6 +312,8 @@ static inline char *mingw_find_last_dir_sep(const char *path) return ret; } #define find_last_dir_sep mingw_find_last_dir_sep +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 6053871bc3..467095df84 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -211,6 +211,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 39b576c298..8745aad206 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From f6b312d7bb9614fe3c5137ad8229bff42eef39df Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 2027/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 4ac4d17f4b..9ac3b9ec69 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 56ea51999af89599abb81b7019c6a951833cebb6 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 2028/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d319e493b5..5bf6982e4e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1825,23 +1825,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From e64238a46d669dbe0b7e0ff1b3432ba08ca09dc0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 2029/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index c5037685e3..0d5bd3465f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 468fd32c01247c443cda1d73959784a521847d9e Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 2030/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 6b18e34726..2a92e20f06 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9480,18 +9480,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9502,6 +9491,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From d42d6f9be18e8b876b443ac8f9e98b76ddc109a2 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 2031/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5bf6982e4e..8f3f64c33c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -668,11 +668,16 @@ char *mingw_getcwd(char *pointer, int len) char *mingw_getenv(const char *name) { char *result = getenv(name); - if (!result && !strcmp(name, "TMPDIR")) { - /* on Windows it is TMP and TEMP */ - result = getenv("TMP"); - if (!result) - result = getenv("TEMP"); + if (!result) { + if (!strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } else if (!strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } } return result; } From fdb236a7871cfe24656c2aa4104dac0c68509a96 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 2032/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index ee3104b6a9..01ce671ab2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -293,9 +293,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From 74c203028006a49afbcea7eb5aa4c4bb631ba7cf Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 2033/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From 4ec659db6bcf6805a5a947bcc6cc5a29bbe40ed0 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 2034/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From 13929ae0fac9855859e644ee000baf9c2bc48ab9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 2035/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index e9457019d5..c0afd976d9 100644 --- a/log-tree.c +++ b/log-tree.c @@ -509,7 +509,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 637cb3d62d0b410f9bc26f21c51f9213b908f28b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 2036/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 240dd4701c..e1ae8f9773 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4216,6 +4216,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 37508f3e1e26fa5600ef614808cc72e5b8f1d14b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 2037/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e1ae8f9773..4b499743ee 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4231,7 +4231,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 041d34ad05a2346d98f090a552f971487569c978 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 2038/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index b2ae8de16d..e9c6d22809 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -138,6 +139,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 8e2b6d93cdc4a73a40bffb95d441055df7e4ceae Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 2039/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index c59b0c98fe..68fd050e94 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die (_("Could not open '%s' for writing."), file); From dedf3a5d2a9f2284b9c725f86659449befe6b039 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 2040/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 2ea4c2bbfe..a638ecd815 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -340,7 +340,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From b307d47739d3d5a5bb6b4eb421eecc4086e2f74e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 2041/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 871afaa3c7..6ef443ec4f 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -178,6 +179,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -188,6 +205,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -505,6 +525,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -956,6 +979,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); From 75bd85e0d552c55c057de7f74292b7bb802cae08 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 2042/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f8c72e10a0..308bd2c3f9 100644 --- a/Makefile +++ b/Makefile @@ -271,7 +271,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From ce974bb756efc43d9100157f66c129db57af33da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 2043/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8f3f64c33c..a2b1a587e6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1810,7 +1810,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From 5a667132e51c7c4a8987d7e408c3ab4bac7a10df Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 2044/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 308bd2c3f9..b2e1759219 100644 --- a/Makefile +++ b/Makefile @@ -1886,7 +1886,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1926,6 +1926,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From b76a5709b9b1c2d4c16fde8064ea0dbd7c280204 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 2045/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index 63849836c8..2ef2ec912e 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From 5267d7b3ef61348c10898b71b59776cc690fbcb7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 2046/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 6ef443ec4f..a953289e90 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1043,6 +1043,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From 02f77e8c176bd18da2e17944b5c1e9e95aff2598 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 2047/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index a953289e90..e7c1c9f0d1 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1043,7 +1043,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From 06d0a8cd505b01f926ab1de21c3c57aa681c5dfe Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 2048/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From d0c163a3a281a09eff9daed0146cca96645f12c0 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 2049/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index a2b1a587e6..17d213dc4c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From bfd06b2069b474b64cf67ae239f165fdd2eeb1b2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 09:29:35 +0200 Subject: [PATCH 2050/3720] MinGW: Skip test redirecting to fd 4 ... because that does not work in MinGW. Signed-off-by: Johannes Schindelin --- t/t0081-line-buffer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index bd83ed371a..25dba008f3 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' ' test_cmp expect actual ' -test_expect_success 'read from file descriptor' ' +test_expect_success NOT_MINGW 'read from file descriptor' ' rm -f input && echo hello >expect && echo hello >input && From c7d531ebfe2ac8cc56600d54e0619e7792a06199 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 16:44:45 +0200 Subject: [PATCH 2051/3720] Disable test on MinGW that challenges its bash quoting Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0d0222ea2a..fae1200255 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -915,7 +915,10 @@ test_expect_success 'remote set-url --add bbb' ' ' test_expect_success 'remote set-url --delete .*' ' - test_must_fail git remote set-url --delete someremote .\* && + if test_have_prereq NOT_MINGW + then + test_must_fail git remote set-url --delete someremote .\* + fi && echo "YYY" >expect && echo baz >>expect && echo bbb >>expect && From b109981bb3d21aff8def422fdaaa3054f48794b5 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Tue, 26 Apr 2011 10:39:30 +0100 Subject: [PATCH 2052/3720] t3102: Windows filesystems may not use a literal asterisk in filenames. Exclude these tests when using MINGW. Signed-off-by: Pat Thoyts --- t/t3102-ls-tree-wildcards.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh index c286854485..766af3de9b 100755 --- a/t/t3102-ls-tree-wildcards.sh +++ b/t/t3102-ls-tree-wildcards.sh @@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs' . ./test-lib.sh -test_expect_success 'setup' ' +test_expect_success NOT_MINGW 'setup' ' mkdir a aa "a[a]" && touch a/one aa/two "a[a]/three" && git add a/one aa/two "a[a]/three" && git commit -m test ' -test_expect_success 'ls-tree a[a] matches literally' ' +test_expect_success NOT_MINGW 'ls-tree a* matches literally' ' cat >expected < Date: Wed, 27 Apr 2011 18:38:04 +0200 Subject: [PATCH 2053/3720] submodule: Use cat instead of echo to avoid DOS line-endings In msysGit, echo used in scripts outputs DOS line-endings while built-ins use Unix line-endings in their output. This causes t7508-status to fail due to mixed line endings in the output of git status (which calls git-submodule). Signed-off-by: Sebastian Schuberth --- git-submodule.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index c571d320d0..1bf19b733c 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -750,12 +750,16 @@ cmd_summary() { done | if test -n "$for_status"; then if [ -n "$files" ]; then - gettext "# Submodules changed but not updated:"; echo + status_msg="$(gettext "# Submodules changed but not updated:")" else - gettext "# Submodule changes to be committed:"; echo + status_msg="$(gettext "# Submodule changes to be committed:")" fi - echo "#" - sed -e 's|^|# |' -e 's|^# $|#|' + status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|') + cat < Date: Sun, 1 May 2011 14:47:09 +0100 Subject: [PATCH 2054/3720] t5407: Fix line-ending dependency in post-rewrite.args On msysGit creating the post-rewrite.args file using 'echo' has different line endings from the expected comparison. Using perl normalizes the line endings for each generated file. Signed-off-by: Pat Thoyts --- t/t5407-post-rewrite-hook.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index baa670cea5..35403b435e 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -20,9 +20,13 @@ test_expect_success 'setup' ' mkdir .git/hooks cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args -cat > "$TRASH_DIRECTORY"/post-rewrite.data +#!/usr/bin/perl +open (AR, ">$TRASH_DIRECTORY/post-rewrite.args"); +print AR \$_,"\n" foreach @ARGV; +open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data"); +while() { + print DAT; +} EOF chmod u+x .git/hooks/post-rewrite From a6ffa18ad0a9db65bceaf576a79b595883de2368 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Thu, 28 Apr 2011 00:30:49 +0200 Subject: [PATCH 2055/3720] submodule: Fix t7400, t7405, t7406 for msysGit Again, avoid using echo (which issues DOS line endings on msysGit) to not mix with Unix line-endings issued by git built-ins, even if this is at the cost of calling an external executable (cat) instead of a shell built-in (echo). --- git-sh-setup.sh | 4 +++- git-submodule.sh | 11 +++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 94e26ed5e8..e3ad57a7e4 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -49,7 +49,9 @@ GIT_QUIET= say () { if test -z "$GIT_QUIET" then - printf '%s\n' "$*" + cat < /dev/null 2>&1 then - ( - eval_gettext "The following path is ignored by one of your .gitignore files: -\$path -Use -f if you really want to add it." && - echo - ) >&2 + cat >&2 < Date: Wed, 15 Jun 2011 16:57:59 +0200 Subject: [PATCH 2056/3720] Revert "MinGW: Add missing file mode bit defines" This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a. --- compat/mingw.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 01ce671ab2..ef5226c7c4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,12 +14,6 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 -#ifndef _STAT_H_ -#define S_IRUSR 0 -#define S_IWUSR 0 -#define S_IXUSR 0 -#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) -#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From fa7502ca2122f4724138a0839dff92d842a486b7 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:34:33 +0100 Subject: [PATCH 2057/3720] Win32 dirent: remove unused dirent.d_ino member There are no proper inodes on Windows, so remove dirent.d_ino and #define NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in fsck.c). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- Makefile | 2 ++ compat/win32/dirent.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b2e1759219..d01f228c91 100644 --- a/Makefile +++ b/Makefile @@ -1106,6 +1106,7 @@ ifeq ($(uname_S),Windows) BLK_SHA1 = YesPlease NO_POSIX_GOODIES = UnfortunatelyYes NATIVE_CRLF = YesPlease + NO_D_INO_IN_DIRENT = YesPlease CC = compat/vcbuild/scripts/clink.pl AR = compat/vcbuild/scripts/lib.pl @@ -1181,6 +1182,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_INET_PTON = YesPlease NO_INET_NTOP = YesPlease NO_POSIX_GOODIES = UnfortunatelyYes + NO_D_INO_IN_DIRENT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/winansi.o \ diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h index 927a25ca76..b38973b051 100644 --- a/compat/win32/dirent.h +++ b/compat/win32/dirent.h @@ -9,7 +9,6 @@ typedef struct DIR DIR; #define DT_LNK 3 struct dirent { - long d_ino; /* Always zero. */ char d_name[FILENAME_MAX]; /* File name. */ union { unsigned short d_reclen; /* Always zero. */ From e46b70f04b98ae25a62fc4c59f28a2d84fd2f58a Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:38:25 +0100 Subject: [PATCH 2058/3720] Win32 dirent: remove unused dirent.d_reclen member Remove the union around dirent.d_type and the unused dirent.d_reclen member (which was necessary for compatibility with the MinGW dirent runtime, which is no longer used). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/win32/dirent.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h index b38973b051..7f4e6c71d9 100644 --- a/compat/win32/dirent.h +++ b/compat/win32/dirent.h @@ -10,10 +10,7 @@ typedef struct DIR DIR; struct dirent { char d_name[FILENAME_MAX]; /* File name. */ - union { - unsigned short d_reclen; /* Always zero. */ - unsigned char d_type; /* Reimplementation adds this */ - }; + unsigned char d_type; /* file type to prevent lstat after readdir */ }; DIR *opendir(const char *dirname); From 94fb49b1b74b63d60ea4ce418a70d6da14044bdf Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:43:14 +0100 Subject: [PATCH 2059/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is used throughout the other Win32 code in Git, and also defines the length of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName, from which we're copying the dirent data). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/win32/dirent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h index 7f4e6c71d9..8838cd61fc 100644 --- a/compat/win32/dirent.h +++ b/compat/win32/dirent.h @@ -9,8 +9,8 @@ typedef struct DIR DIR; #define DT_LNK 3 struct dirent { - char d_name[FILENAME_MAX]; /* File name. */ unsigned char d_type; /* file type to prevent lstat after readdir */ + char d_name[MAX_PATH]; /* file name */ }; DIR *opendir(const char *dirname); From 10c3ca76ae0d752f418145a80fe682c6a465b4ba Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:47:41 +0100 Subject: [PATCH 2060/3720] Win32 dirent: clarify #include directives Git-compat-util.h is two dirs up, and already includes (which is the same as "dirent.h" due to -Icompat/win32 in the Makefile). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/win32/dirent.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c index 7a0debe51b..fac7f25047 100644 --- a/compat/win32/dirent.c +++ b/compat/win32/dirent.c @@ -1,5 +1,4 @@ -#include "../git-compat-util.h" -#include "dirent.h" +#include "../../git-compat-util.h" struct DIR { struct dirent dd_dir; /* includes d_type */ From 03c66d5e2b647ca15948e9d29e46cc36c3fd5617 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:57:02 +0100 Subject: [PATCH 2061/3720] Win32 dirent: improve dirent implementation Improve the dirent implementation by removing the relics that were once necessary to plug into the now unused MinGW runtime, in preparation for Unicode file name support. Move FindFirstFile to opendir, and FindClose to closedir, with the following implications: - DIR.dd_name is no longer needed - chdir(one); opendir(relative); chdir(two); readdir() works as expected (i.e. lists one/relative instead of two/relative) - DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct - thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0 have been removed - the special case that the directory has been fully read (which was previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE && dd_stat != 0) is now handled implicitly by the FindNextFile error handling code (if a client continues to call readdir after receiving NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to the same effect) - extracting dirent data from WIN32_FIND_DATA is needed in two places, so moved to its own method - GetFileAttributes is no longer needed. The same information can be obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if the name is NOT a directory (-> ENOTDIR), otherwise we can use err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this probably breaks other functionality. Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was fortunately a NOOP (searching for '*' always finds '.' and '..'), otherwise the subsequent code would have copied data from an uninitialized buffer). Changes malloc to git support function xmalloc, so opendir will die() if out of memory, rather than failing with ENOMEM and letting git work on incomplete directory listings (error handling in dir.c is quite sparse). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/win32/dirent.c | 111 ++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 58 deletions(-) diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c index fac7f25047..82a515c21b 100644 --- a/compat/win32/dirent.c +++ b/compat/win32/dirent.c @@ -4,92 +4,88 @@ struct DIR { struct dirent dd_dir; /* includes d_type */ HANDLE dd_handle; /* FindFirstFile handle */ int dd_stat; /* 0-based index */ - char dd_name[1]; /* extend struct */ }; +static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) +{ + /* copy file name from WIN32_FIND_DATA to dirent */ + memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name)); + + /* Set file type, based on WIN32_FIND_DATA */ + if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ent->d_type = DT_DIR; + else + ent->d_type = DT_REG; +} + DIR *opendir(const char *name) { - DWORD attrs = GetFileAttributesA(name); + char pattern[MAX_PATH]; + WIN32_FIND_DATAA fdata; + HANDLE h; int len; - DIR *p; + DIR *dir; - /* check for valid path */ - if (attrs == INVALID_FILE_ATTRIBUTES) { - errno = ENOENT; + /* check that name is not NULL */ + if (!name) { + errno = EINVAL; return NULL; } - - /* check if it's a directory */ - if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) { - errno = ENOTDIR; - return NULL; - } - /* check that the pattern won't be too long for FindFirstFileA */ len = strlen(name); - if (is_dir_sep(name[len - 1])) - len--; if (len + 2 >= MAX_PATH) { errno = ENAMETOOLONG; return NULL; } + /* copy name to temp buffer */ + memcpy(pattern, name, len + 1); - p = malloc(sizeof(DIR) + len + 2); - if (!p) + /* append optional '/' and wildcard '*' */ + if (len && !is_dir_sep(pattern[len - 1])) + pattern[len++] = '/'; + pattern[len++] = '*'; + pattern[len] = 0; + + /* open find handle */ + h = FindFirstFileA(pattern, &fdata); + if (h == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError(); + errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); return NULL; + } - memset(p, 0, sizeof(DIR) + len + 2); - strcpy(p->dd_name, name); - p->dd_name[len] = '/'; - p->dd_name[len+1] = '*'; - - p->dd_handle = INVALID_HANDLE_VALUE; - return p; + /* initialize DIR structure and copy first dir entry */ + dir = xmalloc(sizeof(DIR)); + dir->dd_handle = h; + dir->dd_stat = 0; + finddata2dirent(&dir->dd_dir, &fdata); + return dir; } struct dirent *readdir(DIR *dir) { - WIN32_FIND_DATAA buf; - HANDLE handle; - - if (!dir || !dir->dd_handle) { + if (!dir) { errno = EBADF; /* No set_errno for mingw */ return NULL; } - if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) { - DWORD lasterr; - handle = FindFirstFileA(dir->dd_name, &buf); - lasterr = GetLastError(); - dir->dd_handle = handle; - if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { - errno = err_win_to_posix(lasterr); + /* if first entry, dirent has already been set up by opendir */ + if (dir->dd_stat) { + /* get next entry and convert from WIN32_FIND_DATA to dirent */ + WIN32_FIND_DATAA fdata; + if (FindNextFileA(dir->dd_handle, &fdata)) { + finddata2dirent(&dir->dd_dir, &fdata); + } else { + DWORD lasterr = GetLastError(); + /* POSIX says you shouldn't set errno when readdir can't + find any more files; so, if another error we leave it set. */ + if (lasterr != ERROR_NO_MORE_FILES) + errno = err_win_to_posix(lasterr); return NULL; } - } else if (dir->dd_handle == INVALID_HANDLE_VALUE) { - return NULL; - } else if (!FindNextFileA(dir->dd_handle, &buf)) { - DWORD lasterr = GetLastError(); - FindClose(dir->dd_handle); - dir->dd_handle = INVALID_HANDLE_VALUE; - /* POSIX says you shouldn't set errno when readdir can't - find any more files; so, if another error we leave it set. */ - if (lasterr != ERROR_NO_MORE_FILES) - errno = err_win_to_posix(lasterr); - return NULL; } - /* We get here if `buf' contains valid data. */ - strcpy(dir->dd_dir.d_name, buf.cFileName); ++dir->dd_stat; - - /* Set file type, based on WIN32_FIND_DATA */ - dir->dd_dir.d_type = 0; - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - dir->dd_dir.d_type |= DT_DIR; - else - dir->dd_dir.d_type |= DT_REG; - return &dir->dd_dir; } @@ -100,8 +96,7 @@ int closedir(DIR *dir) return -1; } - if (dir->dd_handle != INVALID_HANDLE_VALUE) - FindClose(dir->dd_handle); + FindClose(dir->dd_handle); free(dir); return 0; } From 194ca7c6ed03f15c385424898d8345e9b5254bf2 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 18:04:16 +0100 Subject: [PATCH 2062/3720] Win32: fix potential multi-threading issue ...by removing a static buffer in do_stat_internal. Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 17d213dc4c..68d694808a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; - static char alt_name[PATH_MAX]; + char alt_name[PATH_MAX]; if (!do_lstat(follow, file_name, buf)) return 0; From b11582449b986cdaa97f5e16fe5d769743702143 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 19:47:23 +0100 Subject: [PATCH 2063/3720] Win32: move main macro to a function The code in the MinGW main macro is getting more and more complex, move to a separate initialization function for readabiliy and extensibility. Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 15 +++++++++++++++ compat/mingw.h | 14 ++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 68d694808a..0228f53e76 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1852,3 +1852,18 @@ int mingw_offset_1st_component(const char *path) return offset + is_dir_sep(path[offset]); } + +void mingw_startup() +{ + /* copy executable name to argv[0] */ + __argv[0] = xstrdup(_pgmptr); + + /* initialize critical section for waitpid pinfo_t list */ + InitializeCriticalSection(&pinfo_cs); + + /* set up default file mode and file modes for stdin/out/err */ + _fmode = _O_BINARY; + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); + _setmode(_fileno(stderr), _O_BINARY); +} diff --git a/compat/mingw.h b/compat/mingw.h index ef5226c7c4..a832520c6c 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -327,22 +327,16 @@ char **make_augmented_environ(const char *const *vars); void free_environ(char **env); /* - * A replacement of main() that ensures that argv[0] has a path - * and that default fmode and std(in|out|err) are in binary mode + * A replacement of main() that adds win32 specific initialization. */ +void mingw_startup(); #define main(c,v) dummy_decl_mingw_main(); \ static int mingw_main(); \ int main(int argc, const char **argv) \ { \ - extern CRITICAL_SECTION pinfo_cs; \ - _fmode = _O_BINARY; \ - _setmode(_fileno(stdin), _O_BINARY); \ - _setmode(_fileno(stdout), _O_BINARY); \ - _setmode(_fileno(stderr), _O_BINARY); \ - argv[0] = xstrdup(_pgmptr); \ - InitializeCriticalSection(&pinfo_cs); \ - return mingw_main(argc, argv); \ + mingw_startup(); \ + return mingw_main(__argc, __argv); \ } \ static int mingw_main(c,v) From bf1a7ff510a4ad08c8e05e9905c00a30ec22d37c Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 19:52:20 +0100 Subject: [PATCH 2064/3720] MinGW: disable CRT command line globbing MingwRT listens to _CRT_glob to decide if __getmainargs should perform globbing, with the default being that it should. Unfortunately, __getmainargs globbing is sub-par; for instance patterns like "*.c" will only match c-sources in the current directory. Disable __getmainargs' command line wildcard expansion, so these patterns will be left untouched, and handled by Git's superior built-in globbing instead. MSVC defaults to no globbing, so we don't need to do anything in that case. This fixes t5505 and t7810. Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 0228f53e76..f3517c78f6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1853,6 +1853,12 @@ int mingw_offset_1st_component(const char *path) return offset + is_dir_sep(path[offset]); } +/* + * Disable MSVCRT command line wildcard expansion (__getmainargs called from + * mingw startup code, see init.c in mingw runtime). + */ +int _CRT_glob = 0; + void mingw_startup() { /* copy executable name to argv[0] */ From a03ceba68830fd5112ce33db7f933e763ffdf7f2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jul 2011 19:14:54 +0200 Subject: [PATCH 2065/3720] Do not trust PWD blindly At least on Windows, chdir() does not update PWD. Unfortunately, stat() does not fill any ino or dev fields anymore, so get_pwd_cwd() is not able to tell. But there is a telltale: both ino and dev are 0 when they are not filled correctly, so let's be extra cautious. This happens to fix a bug in "get-receive-pack working_directory/" when the GIT_DIR would not be set correctly due to absolute_path(".") returning the wrong value. Signed-off-by: Johannes Schindelin --- abspath.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/abspath.c b/abspath.c index 01858eb7bc..37287f86c1 100644 --- a/abspath.c +++ b/abspath.c @@ -102,7 +102,8 @@ static const char *get_pwd_cwd(void) pwd = getenv("PWD"); if (pwd && strcmp(pwd, cwd)) { stat(cwd, &cwd_stat); - if (!stat(pwd, &pwd_stat) && + if ((cwd_stat.st_dev || cwd_stat.st_ino) && + !stat(pwd, &pwd_stat) && pwd_stat.st_dev == cwd_stat.st_dev && pwd_stat.st_ino == cwd_stat.st_ino) { strlcpy(cwd, pwd, PATH_MAX); From 59f522602894c4a291ff56d9308b2981cf1c99ed Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:50:34 -0400 Subject: [PATCH 2066/3720] introduce credentials API There are a few places in git that need to get a username and password credential from the user; the most notable one is HTTP authentication for smart-http pushing. Right now the only choices for providing credentials are to put them plaintext into your ~/.netrc, or to have git prompt you (either on the terminal or via an askpass program). The former is not very secure, and the latter is not very convenient. Unfortunately, there is no "always best" solution for password management. The details will depend on the tradeoff you want between security and convenience, as well as how git can integrate with other security systems (e.g., many operating systems provide a keychain or password wallet for single sign-on). This patch abstracts the notion of gathering user credentials into a few simple functions. These functions can be backed by our internal git_getpass implementation (which just prompts the user), or by external helpers which are free to consult system-specific password wallets, make custom policy decisions on password caching and storage, or prompt the user in a non-traditional manner. The helper protocol aims for simplicity of helper implementation; see the newly added documentation for details. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- .gitignore | 1 + Documentation/technical/api-credentials.txt | 113 ++++++++++++ Makefile | 3 + credential.c | 190 ++++++++++++++++++++ credential.h | 19 ++ t/t0300-credentials.sh | 175 ++++++++++++++++++ test-credential.c | 47 +++++ 7 files changed, 548 insertions(+) create mode 100644 Documentation/technical/api-credentials.txt create mode 100644 credential.c create mode 100644 credential.h create mode 100755 t/t0300-credentials.sh create mode 100644 test-credential.c diff --git a/.gitignore b/.gitignore index 8572c8c0b0..7d2fefce96 100644 --- a/.gitignore +++ b/.gitignore @@ -167,6 +167,7 @@ /gitweb/static/gitweb.js /gitweb/static/gitweb.min.* /test-chmtime +/test-credential /test-ctype /test-date /test-delta diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt new file mode 100644 index 0000000000..880db92c69 --- /dev/null +++ b/Documentation/technical/api-credentials.txt @@ -0,0 +1,113 @@ +credentials API +=============== + +The credentials API provides an abstracted way of gathering username and +password credentials from the user (even though credentials in the wider +world can take many forms, in this document the word "credential" always +refers to a username and password pair). + +Data Structures +--------------- + +`struct credential`:: + + This struct represents a single username/password combination. + The `username` and `password` fields should be heap-allocated + strings (or NULL if they are not yet known). The `unique` field, + if non-NULL, should be a heap-allocated string indicating a + unique context for this credential (e.g., a protocol and server + name for a remote credential). The `description` field, if + non-NULL, should point to a string containing a human-readable + description of this credential. + +`struct string_list methods`:: + + The credential functions take a `string_list` of methods for + acquiring credentials. Each string specifies an external + helper which will be run, in order, to acquire credentials, + until both a username and password have been acquired. A NULL or + empty methods list indicates that the internal + `credential_getpass` function should be used. + + +Functions +--------- + +`credential_fill_gently`:: + + Attempt to fill the username and password fields of the passed + credential struct. If they cannot be filled after trying each + available method, returns -1. Otherwise, returns 0. + +`credential_fill`:: + + Like `credential_fill_gently`, but `die()` if credentials cannot + be gathered. + +`credential_reject`:: + + Inform the credential subsystem that the provided credentials + have been rejected. This will clear the username and password + fields in `struct credential`, as well as notify any helpers of + the rejection (which may, for example, purge the invalid + credentials from storage). + +`credential_getpass`:: + + Fetch credentials from the user either using an "askpass" helper + (see the discussion of core.askpass and GIT_ASKPASS in + linkgit:git-config[1] and linkgit:git[1], respectively) or by + prompting the user via the terminal. + + +Credential Helpers +------------------ + +Credential helpers are programs executed by git to fetch credentials +from storage or from the user. The default behavior when no helpers are +defined is to use the internal `credential_askpass` function. + +When a helper is executed, it may receive the following options on the +command line: + +`--reject`:: + + Specify that the provided credential has been rejected; the + helper may take appropriate action to purge any credential + storage or cache. If this option is not given, the helper should + assume a credential is being requested. + +`--description=`:: + + `` will contain a human-readable description of the + credential being requested. If this option is not given, no + description is available. + +`--unique=`:: + + `` will contain a token to uniquely identify the context of + the credential (e.g., a host name for network authentication). + If this option is not given, no context is available. + +`--username=`:: + + `` will contain the username requested by the user. If this + option is not given, no username is available, and the helper + should provide both a username and password. + +The helper should produce a list of items on stdout, each followed by a +newline character. Each item should consist of a key-value pair, separated +by an `=` (equals) sign. The value may contain any bytes except a +newline. When reading the response, git understands the following keys: + +`username`:: + + The username part of the credential. If a username was given to + the helper via `--username`, the new value will override it. + +`password`:: + + The password part of the credential. + +It is perfectly acceptable for a helper to provide only part of a +credential, or nothing at all. diff --git a/Makefile b/Makefile index 4ed7996f7b..5da42d025f 100644 --- a/Makefile +++ b/Makefile @@ -424,6 +424,7 @@ PROGRAM_OBJS += sh-i18n--envsubst.o PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS)) TEST_PROGRAMS_NEED_X += test-chmtime +TEST_PROGRAMS_NEED_X += test-credential TEST_PROGRAMS_NEED_X += test-ctype TEST_PROGRAMS_NEED_X += test-date TEST_PROGRAMS_NEED_X += test-delta @@ -514,6 +515,7 @@ LIB_H += compat/win32/pthread.h LIB_H += compat/win32/syslog.h LIB_H += compat/win32/sys/poll.h LIB_H += compat/win32/dirent.h +LIB_H += credential.h LIB_H += csum-file.h LIB_H += decorate.h LIB_H += delta.h @@ -593,6 +595,7 @@ LIB_OBJS += config.o LIB_OBJS += connect.o LIB_OBJS += convert.o LIB_OBJS += copy.o +LIB_OBJS += credential.o LIB_OBJS += csum-file.o LIB_OBJS += ctype.o LIB_OBJS += date.o diff --git a/credential.c b/credential.c new file mode 100644 index 0000000000..f33c66f126 --- /dev/null +++ b/credential.c @@ -0,0 +1,190 @@ +#include "cache.h" +#include "credential.h" +#include "quote.h" +#include "string-list.h" +#include "run-command.h" + +static char *credential_ask_one(const char *what, const char *desc) +{ + struct strbuf prompt = STRBUF_INIT; + char *r; + + if (desc) + strbuf_addf(&prompt, "%s for '%s': ", what, desc); + else + strbuf_addf(&prompt, "%s: ", what); + + /* FIXME: for usernames, we should do something less magical that + * actually echoes the characters. However, we need to read from + * /dev/tty and not stdio, which is not portable (but getpass will do + * it for us). http.c uses the same workaround. */ + r = git_getpass(prompt.buf); + + strbuf_release(&prompt); + return xstrdup(r); +} + +int credential_getpass(struct credential *c) +{ + + if (!c->username) + c->username = credential_ask_one("Username", c->description); + if (!c->password) + c->password = credential_ask_one("Password", c->description); + return 0; +} + +static int read_credential_response(struct credential *c, FILE *fp) +{ + struct strbuf response = STRBUF_INIT; + + while (strbuf_getline(&response, fp, '\n') != EOF) { + char *key = response.buf; + char *value = strchr(key, '='); + + if (!value) { + warning("bad output from credential helper: %s", key); + strbuf_release(&response); + return -1; + } + *value++ = '\0'; + + if (!strcmp(key, "username")) { + free(c->username); + c->username = xstrdup(value); + } + else if (!strcmp(key, "password")) { + free(c->password); + c->password = xstrdup(value); + } + /* ignore other responses; we don't know what they mean */ + } + + strbuf_release(&response); + return 0; +} + +static int run_credential_helper(struct credential *c, const char *cmd) +{ + struct child_process helper; + const char *argv[] = { NULL, NULL }; + FILE *fp; + int r; + + memset(&helper, 0, sizeof(helper)); + argv[0] = cmd; + helper.argv = argv; + helper.use_shell = 1; + helper.no_stdin = 1; + helper.out = -1; + + if (start_command(&helper)) + return -1; + fp = xfdopen(helper.out, "r"); + + r = read_credential_response(c, fp); + + fclose(fp); + if (finish_command(&helper)) + r = -1; + + return r; +} + +static void add_item(struct strbuf *out, const char *key, const char *value) +{ + if (!value) + return; + strbuf_addf(out, " --%s=", key); + sq_quote_buf(out, value); +} + +static int first_word_is_alnum(const char *s) +{ + for (; *s && *s != ' '; s++) + if (!isalnum(*s)) + return 0; + return 1; +} + +static int credential_do(struct credential *c, const char *method, + const char *extra) +{ + struct strbuf cmd = STRBUF_INIT; + int r; + + if (first_word_is_alnum(method)) + strbuf_addf(&cmd, "git credential-%s", method); + else + strbuf_addstr(&cmd, method); + + if (extra) + strbuf_addf(&cmd, " %s", extra); + + add_item(&cmd, "description", c->description); + add_item(&cmd, "unique", c->unique); + add_item(&cmd, "username", c->username); + + r = run_credential_helper(c, cmd.buf); + + strbuf_release(&cmd); + return r; +} + +void credential_fill(struct credential *c, const struct string_list *methods) +{ + struct strbuf err = STRBUF_INIT; + + if (!credential_fill_gently(c, methods)) + return; + + strbuf_addstr(&err, "unable to get credentials"); + if (c->description) + strbuf_addf(&err, "for '%s'", c->description); + if (methods && methods->nr == 1) + strbuf_addf(&err, "; tried '%s'", methods->items[0].string); + else if (methods) { + int i; + strbuf_addstr(&err, "; tried:"); + for (i = 0; i < methods->nr; i++) + strbuf_addf(&err, "\n %s", methods->items[i].string); + } + die("%s", err.buf); +} + +int credential_fill_gently(struct credential *c, + const struct string_list *methods) +{ + int i; + + if (c->username && c->password) + return 0; + + if (!methods || !methods->nr) + return credential_getpass(c); + + for (i = 0; i < methods->nr; i++) { + if (!credential_do(c, methods->items[i].string, NULL) && + c->username && c->password) + return 0; + } + + return -1; +} + +void credential_reject(struct credential *c, const struct string_list *methods) +{ + int i; + + if (methods && c->username) { + for (i = 0; i < methods->nr; i++) { + /* ignore errors, there's nothing we can do */ + credential_do(c, methods->items[i].string, "--reject"); + } + } + + free(c->username); + c->username = NULL; + free(c->password); + c->password = NULL; +} diff --git a/credential.h b/credential.h new file mode 100644 index 0000000000..383b720bb5 --- /dev/null +++ b/credential.h @@ -0,0 +1,19 @@ +#ifndef CREDENTIAL_H +#define CREDENTIAL_H + +struct credential { + char *description; + char *username; + char *password; + char *unique; +}; + +struct string_list; + +int credential_getpass(struct credential *); + +int credential_fill_gently(struct credential *, const struct string_list *methods); +void credential_fill(struct credential *, const struct string_list *methods); +void credential_reject(struct credential *, const struct string_list *methods); + +#endif /* CREDENTIAL_H */ diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh new file mode 100755 index 0000000000..447e98339e --- /dev/null +++ b/t/t0300-credentials.sh @@ -0,0 +1,175 @@ +#!/bin/sh + +test_description='basic credential helper tests' +. ./test-lib.sh + +# Try a set of credential helpers; the expected +# stdout and stderr should be provided on stdin, +# separated by "--". +check() { + while read line; do + case "$line" in + --) break ;; + *) echo "$line" ;; + esac + done >expect-stdout && + cat >expect-stderr && + test-credential "$@" >stdout 2>stderr && + test_cmp expect-stdout stdout && + test_cmp expect-stderr stderr +} + +test_expect_success 'setup helper scripts' ' + cat >dump <<-\EOF && + whoami=$1; shift + if test $# = 0; then + echo >&2 "$whoami: " + else + for i in "$@"; do + echo >&2 "$whoami: $i" + done + fi + EOF + chmod +x dump && + + cat >git-credential-useless <<-\EOF && + #!/bin/sh + dump useless "$@" + exit 0 + EOF + chmod +x git-credential-useless && + + cat >git-credential-verbatim <<-\EOF && + #!/bin/sh + user=$1; shift + pass=$1; shift + dump verbatim "$@" + test -z "$user" || echo username=$user + test -z "$pass" || echo password=$pass + EOF + chmod +x git-credential-verbatim && + + cat >askpass <<-\EOF && + #!/bin/sh + echo >&2 askpass: $* + echo askpass-result + EOF + chmod +x askpass && + GIT_ASKPASS=askpass && + export GIT_ASKPASS && + + PATH="$PWD:$PATH" +' + +test_expect_success 'credential_fill invokes helper' ' + check "verbatim foo bar" <<-\EOF + username=foo + password=bar + -- + verbatim: + EOF +' + +test_expect_success 'credential_fill invokes multiple helpers' ' + check useless "verbatim foo bar" <<-\EOF + username=foo + password=bar + -- + useless: + verbatim: + EOF +' + +test_expect_success 'credential_fill stops when we get a full response' ' + check "verbatim one two" "verbatim three four" <<-\EOF + username=one + password=two + -- + verbatim: + EOF +' + +test_expect_success 'credential_fill continues through partial response' ' + check "verbatim one \"\"" "verbatim two three" <<-\EOF + username=two + password=three + -- + verbatim: + verbatim: --username=one + EOF +' + +test_expect_success 'credential_fill passes along metadata' ' + check --description=foo --unique=bar "verbatim one two" <<-\EOF + username=one + password=two + -- + verbatim: --description=foo + verbatim: --unique=bar + EOF +' + +test_expect_success 'credential_reject calls all helpers' ' + check --reject --username=foo useless "verbatim one two" <<-\EOF + -- + useless: --reject + useless: --username=foo + verbatim: --reject + verbatim: --username=foo + EOF +' + +test_expect_success 'do not bother rejecting empty credential' ' + check --reject useless <<-\EOF + -- + EOF +' + +test_expect_success 'usernames can be preserved' ' + check --username=one "verbatim \"\" three" <<-\EOF + username=one + password=three + -- + verbatim: --username=one +' + +test_expect_success 'usernames can be overridden' ' + check --username=one "verbatim two three" <<-\EOF + username=two + password=three + -- + verbatim: --username=one + EOF +' + +test_expect_success 'do not bother completing already-full credential' ' + check --username=one --password=two "verbatim three four" <<-\EOF + username=one + password=two + -- + EOF +' + +# We can't test the basic terminal password prompt here because +# getpass() tries too hard to find the real terminal. But if our +# askpass helper is run, we know the internal getpass is working. +test_expect_success 'empty methods falls back to internal getpass' ' + check <<-\EOF + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF +' + +test_expect_success 'internal getpass does not ask for known username' ' + check --username=foo <<-\EOF + username=foo + password=askpass-result + -- + askpass: Password: + EOF +' + +test_done diff --git a/test-credential.c b/test-credential.c new file mode 100644 index 0000000000..3929efd9b0 --- /dev/null +++ b/test-credential.c @@ -0,0 +1,47 @@ +#include "cache.h" +#include "credential.h" +#include "string-list.h" +#include "parse-options.h" + +int main(int argc, const char **argv) +{ + int reject = 0; + struct credential c = { NULL }; + struct string_list methods = STRING_LIST_INIT_NODUP; + const char *const usage[] = { + "test-credential [options] [method...]", + NULL + }; + struct option options[] = { + OPT_BOOLEAN(0, "reject", &reject, "reject"), + OPT_STRING(0, "description", &c.description, "desc", + "description"), + OPT_STRING(0, "unique", &c.unique, "token", + "unique"), + OPT_STRING(0, "username", &c.username, "name", "username"), + OPT_STRING(0, "password", &c.password, "pass", "password"), + OPT_END() + }; + int i; + + argc = parse_options(argc, argv, NULL, options, usage, 0); + for (i = 0; i < argc; i++) + string_list_append(&methods, argv[i]); + /* credential_reject will try to free() */ + if (c.username) + c.username = xstrdup(c.username); + if (c.password) + c.password = xstrdup(c.password); + + if (reject) + credential_reject(&c, &methods); + else + credential_fill(&c, &methods); + + if (c.username) + printf("username=%s\n", c.username); + if (c.password) + printf("password=%s\n", c.password); + + return 0; +} From 41b870190386a5419df7c55d3b3f8722e8744dc4 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:50:53 -0400 Subject: [PATCH 2067/3720] http: use credential API to get passwords This patch converts the http code to use the new credential API, both for http authentication as well as for getting certificate passwords. Most of the code change is simply variable naming (the passwords are now contained inside a struct). The biggest change is determining a "unique" context to pass to the credential API. This patch uses "http:$host" for http authentication and "cert:$file" for opening certificate files. We pass an empty list of methods to the credential API, which means that we will use the internal credential_getpass function. This should yield no behavior change, except that we now print "Password for 'certificate':" instead of "Certificate Password:" when asking for certificate passwords. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- http.c | 94 ++++++++++++++++++++++++------------------- t/t5550-http-fetch.sh | 2 +- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/http.c b/http.c index 89e3cf4bd8..4c047be802 100644 --- a/http.c +++ b/http.c @@ -3,6 +3,7 @@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "credential.h" int data_received; int active_requests; @@ -42,7 +43,7 @@ static long curl_low_speed_time = -1; static int curl_ftp_no_epsv; static const char *curl_http_proxy; static const char *curl_cookie_file; -static char *user_name, *user_pass; +static struct credential http_auth; static const char *user_agent; #if LIBCURL_VERSION_NUM >= 0x071700 @@ -53,7 +54,7 @@ static const char *user_agent; #define CURLOPT_KEYPASSWD CURLOPT_SSLCERTPASSWD #endif -static char *ssl_cert_password; +static struct credential cert_auth; static int ssl_cert_password_required; static struct curl_slist *pragma_header; @@ -211,11 +212,11 @@ static int http_options(const char *var, const char *value, void *cb) static void init_curl_http_auth(CURL *result) { - if (user_name) { + if (http_auth.username) { struct strbuf up = STRBUF_INIT; - if (!user_pass) - user_pass = xstrdup(git_getpass("Password: ")); - strbuf_addf(&up, "%s:%s", user_name, user_pass); + credential_fill(&http_auth, NULL); + strbuf_addf(&up, "%s:%s", + http_auth.username, http_auth.password); curl_easy_setopt(result, CURLOPT_USERPWD, strbuf_detach(&up, NULL)); } @@ -223,18 +224,19 @@ static void init_curl_http_auth(CURL *result) static int has_cert_password(void) { - if (ssl_cert_password != NULL) - return 1; if (ssl_cert == NULL || ssl_cert_password_required != 1) return 0; - /* Only prompt the user once. */ - ssl_cert_password_required = -1; - ssl_cert_password = git_getpass("Certificate Password: "); - if (ssl_cert_password != NULL) { - ssl_cert_password = xstrdup(ssl_cert_password); - return 1; - } else - return 0; + if (!cert_auth.description) + cert_auth.description = "certificate"; + if (!cert_auth.unique) { + struct strbuf unique = STRBUF_INIT; + strbuf_addf(&unique, "cert:%s", ssl_cert); + cert_auth.unique = strbuf_detach(&unique, NULL); + } + if (!cert_auth.username) + cert_auth.username = xstrdup(""); + credential_fill(&cert_auth, NULL); + return 1; } static CURL *get_curl_handle(void) @@ -263,7 +265,7 @@ static CURL *get_curl_handle(void) if (ssl_cert != NULL) curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert); if (has_cert_password()) - curl_easy_setopt(result, CURLOPT_KEYPASSWD, ssl_cert_password); + curl_easy_setopt(result, CURLOPT_KEYPASSWD, cert_auth.password); #if LIBCURL_VERSION_NUM >= 0x070903 if (ssl_key != NULL) curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key); @@ -307,10 +309,12 @@ static CURL *get_curl_handle(void) static void http_auth_init(const char *url) { - char *at, *colon, *cp, *slash; + const char *at, *colon, *cp, *slash, *host, *proto_end; + char *decoded; + struct strbuf unique = STRBUF_INIT; - cp = strstr(url, "://"); - if (!cp) + proto_end = strstr(url, "://"); + if (!proto_end) return; /* @@ -319,20 +323,31 @@ static void http_auth_init(const char *url) * "proto://@/...", or just * "proto:///..."? */ - cp += 3; + cp = proto_end + 3; at = strchr(cp, '@'); colon = strchr(cp, ':'); slash = strchrnul(cp, '/'); - if (!at || slash <= at) - return; /* No credentials */ - if (!colon || at <= colon) { - /* Only username */ - user_name = url_decode_mem(cp, at - cp); - user_pass = NULL; - } else { - user_name = url_decode_mem(cp, colon - cp); - user_pass = url_decode_mem(colon + 1, at - (colon + 1)); + + if (!at || slash <= at) { + /* No credentials, but we may have to ask for some later */ + host = cp; } + else if (!colon || at <= colon) { + /* Only username */ + http_auth.username = url_decode_mem(cp, at - cp); + host = at + 1; + } else { + http_auth.username = url_decode_mem(cp, colon - cp); + http_auth.password = url_decode_mem(colon + 1, at - (colon + 1)); + host = at + 1; + } + + strbuf_add(&unique, url, proto_end - url); + strbuf_addch(&unique, ':'); + decoded = url_decode_mem(host, slash - host); + strbuf_addstr(&unique, decoded); + free(decoded); + http_auth.unique = strbuf_detach(&unique, NULL); } static void set_from_env(const char **var, const char *envname) @@ -456,10 +471,10 @@ void http_cleanup(void) curl_http_proxy = NULL; } - if (ssl_cert_password != NULL) { - memset(ssl_cert_password, 0, strlen(ssl_cert_password)); - free(ssl_cert_password); - ssl_cert_password = NULL; + if (cert_auth.password) { + memset(cert_auth.password, 0, strlen(cert_auth.password)); + free(cert_auth.password); + cert_auth.password = NULL; } ssl_cert_password_required = 0; } @@ -819,16 +834,11 @@ static int http_request(const char *url, void *result, int target, int options) else if (missing_target(&results)) ret = HTTP_MISSING_TARGET; else if (results.http_code == 401) { - if (user_name) { + if (http_auth.username) { + credential_reject(&http_auth, NULL); ret = HTTP_NOAUTH; } else { - /* - * git_getpass is needed here because its very likely stdin/stdout are - * pipes to our parent process. So we instead need to use /dev/tty, - * but that is non-portable. Using git_getpass() can at least be stubbed - * on other platforms with a different implementation if/when necessary. - */ - user_name = xstrdup(git_getpass("Username: ")); + credential_fill(&http_auth, NULL); init_curl_http_auth(slot->curl); ret = HTTP_REAUTH; } diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index ed4db09bed..af3bc6bad4 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -66,7 +66,7 @@ test_expect_success 'cloning password-protected repository can fail' ' test_expect_success 'http auth can use user/pass in URL' ' >askpass-query && - echo wrong >askpass-reponse && + echo wrong >askpass-response && git clone "$HTTPD_URL_USER_PASS/auth/repo.git" clone-auth-none && test_cmp askpass-expect-none askpass-query ' From 20a93d32fa7de2f097cb0bc1acfc5a6182db9cd3 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:51:08 -0400 Subject: [PATCH 2068/3720] look for credentials in config before prompting When an http request receives a 401, we ask the user for both a username and password. While it's generally not a good idea for us to store the password in plaintext, having to input the username each time is annoying, and can be easily solved with a config variable. This patch teaches the credential subsystem to look up items in the git config file before prompting. Items are indexed by the "unique" token passed to the credential system. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- credential.c | 38 ++++++++++++++++++++++++++++++++++++++ credential.h | 1 + t/t0300-credentials.sh | 10 ++++++++++ t/t5550-http-fetch.sh | 8 ++++++++ 4 files changed, 57 insertions(+) diff --git a/credential.c b/credential.c index f33c66f126..907b90bad1 100644 --- a/credential.c +++ b/credential.c @@ -4,6 +4,43 @@ #include "string-list.h" #include "run-command.h" +static int credential_config_callback(const char *var, const char *value, + void *data) +{ + struct credential *c = data; + + if (!value) + return 0; + + var = skip_prefix(var, "credential."); + if (!var) + return 0; + + var = skip_prefix(var, c->unique); + if (!var) + return 0; + + if (*var != '.') + return 0; + var++; + + if (!strcmp(var, "username")) { + if (!c->username) + c->username = xstrdup(value); + } + else if (!strcmp(var, "password")) { + free(c->password); + c->password = xstrdup(value); + } + return 0; +} + +void credential_from_config(struct credential *c) +{ + if (c->unique) + git_config(credential_config_callback, c); +} + static char *credential_ask_one(const char *what, const char *desc) { struct strbuf prompt = STRBUF_INIT; @@ -26,6 +63,7 @@ static char *credential_ask_one(const char *what, const char *desc) int credential_getpass(struct credential *c) { + credential_from_config(c); if (!c->username) c->username = credential_ask_one("Username", c->description); diff --git a/credential.h b/credential.h index 383b720bb5..30a0156c0f 100644 --- a/credential.h +++ b/credential.h @@ -11,6 +11,7 @@ struct credential { struct string_list; int credential_getpass(struct credential *); +void credential_from_config(struct credential *); int credential_fill_gently(struct credential *, const struct string_list *methods); void credential_fill(struct credential *, const struct string_list *methods); diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 447e98339e..68d838c26d 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -172,4 +172,14 @@ test_expect_success 'internal getpass does not ask for known username' ' EOF ' +test_expect_success 'internal getpass can pull from config' ' + git config credential.foo.username configured-username + check --unique=foo <<-\EOF + username=configured-username + password=askpass-result + -- + askpass: Password: + EOF +' + test_done diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index af3bc6bad4..c78baaf345 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -85,6 +85,14 @@ test_expect_success 'http auth can request both user and pass' ' test_cmp askpass-expect-both askpass-query ' +test_expect_success 'http auth can pull user from config' ' + >askpass-query && + echo user@host >askpass-response && + git config --global credential.$HTTPD_PROTO:$HTTPD_DEST.username user@host && + git clone "$HTTPD_URL/auth/repo.git" clone-auth-config && + test_cmp askpass-expect-pass askpass-query +' + test_expect_success 'fetch changes via http' ' echo content >>file && git commit -a -m two && From 00b1daa2c109e1d4ccf67b6f92736dbd422d2ba8 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:51:26 -0400 Subject: [PATCH 2069/3720] allow the user to configure credential helpers The functionality for helpers is already there; we just need to give the users a way to turn it on. The new functionality is enabled whenever a caller of the credentials API passes a NULL method list. This will enable it for all current callers (i.e., the http code). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/technical/api-credentials.txt | 5 ++-- config.c | 4 +++ credential.c | 31 ++++++++++++++++++--- credential.h | 2 ++ t/t5550-http-fetch.sh | 13 +++++++++ 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt index 880db92c69..335a007354 100644 --- a/Documentation/technical/api-credentials.txt +++ b/Documentation/technical/api-credentials.txt @@ -25,8 +25,9 @@ Data Structures The credential functions take a `string_list` of methods for acquiring credentials. Each string specifies an external helper which will be run, in order, to acquire credentials, - until both a username and password have been acquired. A NULL or - empty methods list indicates that the internal + until both a username and password have been acquired. A NULL + parameter means to use the default list (as configured by + `credential.helper`); an empty list indicates that the internal `credential_getpass` function should be used. diff --git a/config.c b/config.c index 6b61a849d2..cd2d61e3cb 100644 --- a/config.c +++ b/config.c @@ -9,6 +9,7 @@ #include "exec_cmd.h" #include "strbuf.h" #include "quote.h" +#include "credential.h" #define MAXNAME (256) @@ -791,6 +792,9 @@ int git_default_config(const char *var, const char *value, void *dummy) return 0; } + if (!prefixcmp(var, "credential.")) + return git_default_credential_config(var, value); + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/credential.c b/credential.c index 907b90bad1..7a0c751363 100644 --- a/credential.c +++ b/credential.c @@ -4,6 +4,8 @@ #include "string-list.h" #include "run-command.h" +static struct string_list default_methods; + static int credential_config_callback(const char *var, const char *value, void *data) { @@ -173,15 +175,18 @@ void credential_fill(struct credential *c, const struct string_list *methods) { struct strbuf err = STRBUF_INIT; + if (!methods) + methods = &default_methods; + if (!credential_fill_gently(c, methods)) return; strbuf_addstr(&err, "unable to get credentials"); if (c->description) strbuf_addf(&err, "for '%s'", c->description); - if (methods && methods->nr == 1) + if (methods->nr == 1) strbuf_addf(&err, "; tried '%s'", methods->items[0].string); - else if (methods) { + else { int i; strbuf_addstr(&err, "; tried:"); for (i = 0; i < methods->nr; i++) @@ -198,7 +203,10 @@ int credential_fill_gently(struct credential *c, if (c->username && c->password) return 0; - if (!methods || !methods->nr) + if (!methods) + methods = &default_methods; + + if (!methods->nr) return credential_getpass(c); for (i = 0; i < methods->nr; i++) { @@ -214,7 +222,10 @@ void credential_reject(struct credential *c, const struct string_list *methods) { int i; - if (methods && c->username) { + if (!methods) + methods = &default_methods; + + if (c->username) { for (i = 0; i < methods->nr; i++) { /* ignore errors, there's nothing we can do */ credential_do(c, methods->items[i].string, "--reject"); @@ -226,3 +237,15 @@ void credential_reject(struct credential *c, const struct string_list *methods) free(c->password); c->password = NULL; } + +int git_default_credential_config(const char *var, const char *value) +{ + if (!strcmp(var, "credential.helper")) { + if (!value) + return config_error_nonbool(var); + string_list_append(&default_methods, xstrdup(value)); + return 0; + } + + return 0; +} diff --git a/credential.h b/credential.h index 30a0156c0f..788ed8e8bf 100644 --- a/credential.h +++ b/credential.h @@ -17,4 +17,6 @@ int credential_fill_gently(struct credential *, const struct string_list *method void credential_fill(struct credential *, const struct string_list *methods); void credential_reject(struct credential *, const struct string_list *methods); +int git_default_credential_config(const char *var, const char *value); + #endif /* CREDENTIAL_H */ diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index c78baaf345..407e1cb3c6 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -93,6 +93,19 @@ test_expect_success 'http auth can pull user from config' ' test_cmp askpass-expect-pass askpass-query ' +test_expect_success 'http auth respects credential helpers' ' + cat >credential-helper <<-\EOF && + #!/bin/sh + echo username=user@host + echo password=user@host + EOF + chmod +x credential-helper && + git config --global credential.helper "\"$PWD/credential-helper\"" && + >askpass-query && + git clone "$HTTPD_URL/auth/repo.git" clone-auth-helper && + test_cmp askpass-expect-none askpass-query +' + test_expect_success 'fetch changes via http' ' echo content >>file && git commit -a -m two && From dad8534f864120bb47dce6e7e6a6d523144f5216 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:52:32 -0400 Subject: [PATCH 2070/3720] http: use hostname in credential description Until now, a request for an http password looked like: Username: Password: Now it will look like: Username for 'example.com': Password for 'example.com': Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- http.c | 7 +++---- t/t5550-http-fetch.sh | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/http.c b/http.c index 4c047be802..d6b2d783ff 100644 --- a/http.c +++ b/http.c @@ -310,7 +310,6 @@ static CURL *get_curl_handle(void) static void http_auth_init(const char *url) { const char *at, *colon, *cp, *slash, *host, *proto_end; - char *decoded; struct strbuf unique = STRBUF_INIT; proto_end = strstr(url, "://"); @@ -342,11 +341,11 @@ static void http_auth_init(const char *url) host = at + 1; } + http_auth.description = url_decode_mem(host, slash - host); + strbuf_add(&unique, url, proto_end - url); strbuf_addch(&unique, ':'); - decoded = url_decode_mem(host, slash - host); - strbuf_addstr(&unique, decoded); - free(decoded); + strbuf_addstr(&unique, http_auth.description); http_auth.unique = strbuf_detach(&unique, NULL); } diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index 407e1cb3c6..b04261cfb5 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -51,8 +51,8 @@ test_expect_success 'setup askpass helpers' ' GIT_ASKPASS="$PWD/askpass" && export GIT_ASKPASS && >askpass-expect-none && - echo "askpass: Password: " >askpass-expect-pass && - { echo "askpass: Username: " && + echo "askpass: Password for '\''$HTTPD_DEST'\'': " >askpass-expect-pass && + { echo "askpass: Username for '\''$HTTPD_DEST'\'': " && cat askpass-expect-pass } >askpass-expect-both ' From b0c3e61f4d53b59dbf48f76ed730fc4d4c004cc6 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:52:47 -0400 Subject: [PATCH 2071/3720] docs: end-user documentation for the credential subsystem The credential API and helper format is already defined in technical/api-credentials.txt. This presents the end-user view. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/Makefile | 1 + Documentation/config.txt | 11 +++ Documentation/gitcredentials.txt | 139 +++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 Documentation/gitcredentials.txt diff --git a/Documentation/Makefile b/Documentation/Makefile index 36989b7f65..88e7f4774f 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -7,6 +7,7 @@ MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt githooks.txt \ MAN7_TXT=gitcli.txt gittutorial.txt gittutorial-2.txt \ gitcvs-migration.txt gitcore-tutorial.txt gitglossary.txt \ gitdiffcore.txt gitrevisions.txt gitworkflows.txt +MAN7_TXT += gitcredentials.txt MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT) MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT)) diff --git a/Documentation/config.txt b/Documentation/config.txt index b56959b5dc..13c13f4b84 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -823,6 +823,17 @@ commit.template:: "{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the specified user's home directory. +credential.helper:: + Specify an external helper to be called when a username or + password credential is needed; the helper may consult external + storage to avoid prompting the user for the credentials. See + linkgit:gitcredentials[7] for details. + +credential..username:: + Specify a default username to be used instead of prompting the + user when getting credentials for ``. See + linkgit:gitcredentials[7] for details. + include::diff-config.txt[] difftool..path:: diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt new file mode 100644 index 0000000000..74136ee03a --- /dev/null +++ b/Documentation/gitcredentials.txt @@ -0,0 +1,139 @@ +gitcredentials(7) +================= + +NAME +---- +gitcredentials - providing usernames and passwords to git + +SYNOPSIS +-------- +------------------ +git config credential.https:example.com.username myusername +git config credential.helper "$helper $options" +------------------ + +DESCRIPTION +----------- + +Git will sometimes need credentials from the user in order to perform +operations; for example, it may need to ask for a username and password +in order to access a remote repository over HTTP. This manual describes +the mechanisms git uses to request these credentials, as well as some +features to avoid inputting these credentials repeatedly. + +REQUESTING CREDENTIALS +---------------------- + +Without any credential helpers defined, git will try the following +strategies to ask the user for usernames and passwords: + +1. If the `GIT_ASKPASS` environment variable is set, the program + specified by the variable is invoked. A suitable prompt is provided + to the program on the command line, and the user's input is read + from its standard output. + +2. Otherwise, if the `core.askpass` configuration variable is set, its + value is used as above. + +3. Otherwise, if the `SSH_ASKPASS` environment variable is set, its + value is used as above. + +4. Otherwise, the user is prompted on the terminal. + +AVOIDING REPETITION +------------------- + +It can be cumbersome to input the same credentials over and over. Git +provides two methods to reduce this annoyance: + +1. Static configuration of usernames for a given authentication context. + +2. Credential helpers to cache or store passwords, or to interact with + a system password wallet or keychain. + +STATIC CONFIGURATION +-------------------- + +Git can look for credential information in your git config files. Note +that it only makes sense to store usernames, not passwords, as git +config files are not encrypted or usually even protected by filesystem +permissions. + +For a given credential request, git uses a unique token to represent the +context of a request. For example, a request to +`https://example.com/repo.git` would have the context +`https:example.com`. See `CONTEXT TOKENS` below for a full list. + +To statically configure a username, set the configuration variable +`credential.$token.username`. For example, in this instance git will +prompt only for the password, not the username: + +-------------------------------------------------------------- +$ git config --global credential.https:example.com.username me +$ git push https://example.com/repo.git +Password: +-------------------------------------------------------------- + +CREDENTIAL HELPERS +------------------ + +Credential helpers are external programs from which git can request +usernames and passwords. + +To use a helper, you must first select one to use. Git does not yet +include any credential helpers, but you may have third-party helpers +installed; search for `credential-*` in the output of `git help -a`, and +consult the documentation of individual helpers. Once you have selected +a helper, you can tell git to use it by putting its name into the +credential.helper variable. + +1. Find a helper. ++ +------------------------------------------- +$ git help -a | grep credential- +credential-foo +------------------------------------------- + +2. Read its description. ++ +------------------------------------------- +$ git help credential-foo +------------------------------------------- + +3. Tell git to use it. ++ +------------------------------------------- +$ git config --global credential.helper foo +------------------------------------------- + +If there are multiple instances of the `credential.helper` configuration +variable, each helper will be tried in turn, and may provide a username, +password, or nothing. Once git has acquired both a username and a +password, no more helpers will be tried. + +CUSTOM HELPERS +-------------- + +You can write your own custom helpers to interface with any system in +which you keep credentials. See the documentation for git's +link:technical/api-credentials.html[credentials API] for details. + +CONTEXT TOKENS +-------------- + +The full set of unique context tokens provided by git to credential +helpers is: + +`$protocol:$hostname`:: + + A network request to a specific host. `$protocol` is + either `http` or `https`, and `$hostname` is the hostname + provided to git (which may not be fully qualified). + +`cert:$filename`:: + + A password to decrypt a certificate on disk. + +GIT +--- +Part of the linkgit:git[1] suite From 2d6874d83a71b330e51475fd2f6dafedcfeecb44 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:55:12 -0400 Subject: [PATCH 2072/3720] credentials: add "cache" helper If you access repositories over smart-http using http authentication, then it can be annoying to have git ask you for your password repeatedly. We cache credentials in memory, of course, but git is composed of many small programs. Having to input your password for each one can be frustrating. This patch introduces a credential helper that will cache passwords in memory for a short period of time. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- .gitignore | 2 + .../git-credential-cache--daemon.txt | 26 ++ Documentation/git-credential-cache.txt | 84 ++++++ Documentation/gitcredentials.txt | 17 +- Makefile | 3 + credential-cache--daemon.c | 268 ++++++++++++++++++ credential-cache.c | 163 +++++++++++ git-compat-util.h | 1 + t/t0300-credentials.sh | 91 ++++++ unix-socket.c | 58 ++++ unix-socket.h | 7 + 11 files changed, 715 insertions(+), 5 deletions(-) create mode 100644 Documentation/git-credential-cache--daemon.txt create mode 100644 Documentation/git-credential-cache.txt create mode 100644 credential-cache--daemon.c create mode 100644 credential-cache.c create mode 100644 unix-socket.c create mode 100644 unix-socket.h diff --git a/.gitignore b/.gitignore index 7d2fefce96..a6b0bd4035 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,8 @@ /git-commit-tree /git-config /git-count-objects +/git-credential-cache +/git-credential-cache--daemon /git-cvsexportcommit /git-cvsimport /git-cvsserver diff --git a/Documentation/git-credential-cache--daemon.txt b/Documentation/git-credential-cache--daemon.txt new file mode 100644 index 0000000000..11edc5a173 --- /dev/null +++ b/Documentation/git-credential-cache--daemon.txt @@ -0,0 +1,26 @@ +git-credential-cache--daemon(1) +=============================== + +NAME +---- +git-credential-cache--daemon - temporarily store user credentials in memory + +SYNOPSIS +-------- +[verse] +git credential-cache--daemon + +DESCRIPTION +----------- + +NOTE: You probably don't want to invoke this command yourself; it is +started automatically when you use linkgit:git-credential-cache[1]. + +This command listens on the Unix domain socket specified by `` +for `git-credential-cache` clients. Clients may store and retrieve +credentials. Each credential is held for a timeout specified by the +client; once no credentials are held, the daemon exits. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt new file mode 100644 index 0000000000..563fdae6fb --- /dev/null +++ b/Documentation/git-credential-cache.txt @@ -0,0 +1,84 @@ +git-credential-cache(1) +======================= + +NAME +---- +git-credential-cache - helper to temporarily store passwords in memory + +SYNOPSIS +-------- +----------------------------- +git config credential.helper 'cache [options]' +----------------------------- + +DESCRIPTION +----------- + +This command requests credentials from the user and caches them in +memory for use by future git programs. The stored credentials never +touch the disk, and are forgotten after a configurable timeout. The +cache is accessible over a Unix domain socket, restricted to the current +user by filesystem permissions. + +You probably don't want to invoke this command directly; it is meant to +be used as a credential helper by other parts of git. See +linkgit:gitcredentials[7] or `EXAMPLES` below. + +OPTIONS +------- + +--timeout:: + + Number of seconds to cache credentials (default: 900). + +--socket :: + + Use `` to contact a running cache daemon (or start a new + cache daemon if one is not started). Defaults to + `~/.git-credential-cache/socket`. If your home directory is on a + network-mounted filesystem, you may need to change this to a + local filesystem. + +--chain :: + + Specify an external helper to use for retrieving credentials + from the user, instead of the default method. The resulting + credentials are then cached as normal. This option can be + given multiple times; each chained helper will be tried until + credentials are received. + +--exit:: + + Tell a running daemon to exit, forgetting all cached + credentials. + +Git may provide other options to the program when it is called as a +credential helper; see linkgit:gitcredentials[7]. + +EXAMPLES +-------- + +The point of this helper is to reduce the number of times you must type +your username or password. For example: + +------------------------------------ +$ git config credential.helper cache +$ git push http://example.com/repo.git +Username: +Password: + +[work for 5 more minutes] +$ git push http://example.com/repo.git +[your credentials are used automatically] +------------------------------------ + +You can provide options via the credential.helper configuration +variable (this example drops the cache time to 5 minutes): + +------------------------------------ +$ git config credential.helper 'cache --timeout=300' +------------------------------------ + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt index 74136ee03a..bd1a3b66f3 100644 --- a/Documentation/gitcredentials.txt +++ b/Documentation/gitcredentials.txt @@ -80,11 +80,18 @@ CREDENTIAL HELPERS Credential helpers are external programs from which git can request usernames and passwords. -To use a helper, you must first select one to use. Git does not yet -include any credential helpers, but you may have third-party helpers -installed; search for `credential-*` in the output of `git help -a`, and -consult the documentation of individual helpers. Once you have selected -a helper, you can tell git to use it by putting its name into the +To use a helper, you must first select one to use. Git currently +includes the following helpers: + +cache:: + + Cache credentials in memory for a short period of time. See + linkgit:git-credential-cache[1] for details. + +You may may also have third-party helpers installed; search for +`credential-*` in the output of `git help -a`, and consult the +documentation of individual helpers. Once you have selected a helper, +you can tell git to use it by putting its name into the credential.helper variable. 1. Find a helper. diff --git a/Makefile b/Makefile index 5da42d025f..442e249b08 100644 --- a/Makefile +++ b/Makefile @@ -420,6 +420,8 @@ PROGRAM_OBJS += show-index.o PROGRAM_OBJS += upload-pack.o PROGRAM_OBJS += http-backend.o PROGRAM_OBJS += sh-i18n--envsubst.o +PROGRAM_OBJS += credential-cache.o +PROGRAM_OBJS += credential-cache--daemon.o PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS)) @@ -680,6 +682,7 @@ LIB_OBJS += transport-helper.o LIB_OBJS += tree-diff.o LIB_OBJS += tree.o LIB_OBJS += tree-walk.o +LIB_OBJS += unix-socket.o LIB_OBJS += unpack-trees.o LIB_OBJS += url.o LIB_OBJS += usage.o diff --git a/credential-cache--daemon.c b/credential-cache--daemon.c new file mode 100644 index 0000000000..f520347f60 --- /dev/null +++ b/credential-cache--daemon.c @@ -0,0 +1,268 @@ +#include "cache.h" +#include "credential.h" +#include "unix-socket.h" + +struct credential_cache_entry { + struct credential item; + unsigned long expiration; +}; +static struct credential_cache_entry *entries; +static int entries_nr; +static int entries_alloc; + +static void cache_credential(const struct credential *c, int timeout) +{ + struct credential_cache_entry *e; + + ALLOC_GROW(entries, entries_nr + 1, entries_alloc); + e = &entries[entries_nr++]; + + memcpy(&e->item, c, sizeof(*c)); + e->expiration = time(NULL) + timeout; +} + +static struct credential_cache_entry *lookup_credential(const struct credential *c) +{ + int i; + for (i = 0; i < entries_nr; i++) { + struct credential *e = &entries[i].item; + + /* We must either both have the same unique token, + * or we must not be using unique tokens at all. */ + if (e->unique) { + if (!c->unique || strcmp(e->unique, c->unique)) + continue; + } + else if (c->unique) + continue; + + /* If we have a username, it must match. Otherwise, + * we will fill in the username. */ + if (c->username && strcmp(e->username, c->username)) + continue; + + return &entries[i]; + } + return NULL; +} + +static void remove_credential(const struct credential *c) +{ + struct credential_cache_entry *e; + + e = lookup_credential(c); + if (e) + e->expiration = 0; +} + +static int check_expirations(void) +{ + int i = 0; + unsigned long now = time(NULL); + unsigned long next = (unsigned long)-1; + + while (i < entries_nr) { + if (entries[i].expiration <= now) { + entries_nr--; + if (!entries_nr) + return 0; + free(entries[i].item.description); + free(entries[i].item.unique); + free(entries[i].item.username); + free(entries[i].item.password); + memcpy(&entries[i], &entries[entries_nr], sizeof(*entries)); + } + else { + if (entries[i].expiration < next) + next = entries[i].expiration; + i++; + } + } + + return next - now; +} + +static int read_credential_request(FILE *fh, struct credential *c, + char **action, int *timeout) { + struct strbuf item = STRBUF_INIT; + + while (strbuf_getline(&item, fh, '\0') != EOF) { + char *key = item.buf; + char *value = strchr(key, '='); + + if (!value) { + warning("cache client sent bogus input: %s", key); + strbuf_release(&item); + return -1; + } + *value++ = '\0'; + + if (!strcmp(key, "action")) + *action = xstrdup(value); + else if (!strcmp(key, "unique")) + c->unique = xstrdup(value); + else if (!strcmp(key, "username")) + c->username = xstrdup(value); + else if (!strcmp(key, "password")) + c->password = xstrdup(value); + else if (!strcmp(key, "timeout")) + *timeout = atoi(value); + else { + warning("cache client sent bogus key: %s", key); + strbuf_release(&item); + return -1; + } + } + strbuf_release(&item); + return 0; +} + +static void serve_one_client(FILE *in, FILE *out) +{ + struct credential c = { NULL }; + int timeout = -1; + char *action = NULL; + + if (read_credential_request(in, &c, &action, &timeout) < 0) + return; + + if (!action) { + warning("cache client didn't specify an action"); + return; + } + + if (!strcmp(action, "exit")) + exit(0); + + if (!strcmp(action, "get")) { + struct credential_cache_entry *e = lookup_credential(&c); + if (e) { + fprintf(out, "username=%s\n", e->item.username); + fprintf(out, "password=%s\n", e->item.password); + } + return; + } + + if (!strcmp(action, "erase")) { + remove_credential(&c); + return; + } + + if (!strcmp(action, "store")) { + if (timeout < 0) { + warning("cache client didn't specify a timeout"); + return; + } + + remove_credential(&c); + cache_credential(&c, timeout); + return; + } + + warning("cache client sent unknown action: %s", action); + return; +} + +static int serve_cache_loop(int fd) +{ + struct pollfd pfd; + unsigned long wakeup; + + wakeup = check_expirations(); + if (!wakeup) + return 0; + + pfd.fd = fd; + pfd.events = POLLIN; + if (poll(&pfd, 1, 1000 * wakeup) < 0) { + if (errno != EINTR) + die_errno("poll failed"); + return 1; + } + + if (pfd.revents & POLLIN) { + int client, client2; + FILE *in, *out; + + client = accept(fd, NULL, NULL); + if (client < 0) { + warning("accept failed: %s", strerror(errno)); + return 1; + } + client2 = dup(client); + if (client2 < 0) { + warning("dup failed: %s", strerror(errno)); + close(client); + return 1; + } + + in = xfdopen(client, "r"); + out = xfdopen(client2, "w"); + serve_one_client(in, out); + fclose(in); + fclose(out); + } + return 1; +} + +static void serve_cache(const char *socket_path) +{ + int fd; + + fd = unix_stream_listen(socket_path); + if (fd < 0) + die_errno("unable to bind to '%s'", socket_path); + + printf("ok\n"); + fclose(stdout); + + while (serve_cache_loop(fd)) + ; /* nothing */ + + close(fd); + unlink(socket_path); +} + +static const char permissions_advice[] = +"The permissions on your socket directory are too loose; other\n" +"users may be able to read your cached credentials. Consider running:\n" +"\n" +" chmod 0700 %s"; +static void check_socket_directory(const char *path) +{ + struct stat st; + char *path_copy = xstrdup(path); + char *dir = dirname(path_copy); + + if (!stat(dir, &st)) { + if (st.st_mode & 077) + die(permissions_advice, dir); + free(path_copy); + return; + } + + /* + * We must be sure to create the directory with the correct mode, + * not just chmod it after the fact; otherwise, there is a race + * condition in which somebody can chdir to it, sleep, then try to open + * our protected socket. + */ + if (safe_create_leading_directories_const(dir) < 0) + die_errno("unable to create directories for '%s'", dir); + if (mkdir(dir, 0700) < 0) + die_errno("unable to mkdir '%s'", dir); + free(path_copy); +} + +int main(int argc, const char **argv) +{ + const char *socket_path = argv[1]; + + if (!socket_path) + die("usage: git-credential-cache--daemon "); + check_socket_directory(socket_path); + + serve_cache(socket_path); + + return 0; +} diff --git a/credential-cache.c b/credential-cache.c new file mode 100644 index 0000000000..f495043ad6 --- /dev/null +++ b/credential-cache.c @@ -0,0 +1,163 @@ +#include "cache.h" +#include "credential.h" +#include "string-list.h" +#include "parse-options.h" +#include "unix-socket.h" +#include "run-command.h" + +static int send_request(const char *socket, const struct strbuf *out) +{ + int got_data = 0; + int fd = unix_stream_connect(socket); + + if (fd < 0) + return -1; + + if (write_in_full(fd, out->buf, out->len) < 0) + die_errno("unable to write to cache daemon"); + shutdown(fd, SHUT_WR); + + while (1) { + char in[1024]; + int r; + + r = read_in_full(fd, in, sizeof(in)); + if (r == 0) + break; + if (r < 0) + die_errno("read error from cache daemon"); + write_or_die(1, in, r); + got_data = 1; + } + return got_data; +} + +static void out_str(struct strbuf *out, const char *key, const char *value) +{ + if (!value) + return; + strbuf_addf(out, "%s=%s", key, value); + strbuf_addch(out, '\0'); +} + +static void out_int(struct strbuf *out, const char *key, int value) +{ + strbuf_addf(out, "%s=%d", key, value); + strbuf_addch(out, '\0'); +} + +static int do_cache(const char *socket, const char *action, + const struct credential *c, int timeout) +{ + struct strbuf buf = STRBUF_INIT; + int ret; + + out_str(&buf, "action", action); + if (c) { + out_str(&buf, "unique", c->unique); + out_str(&buf, "username", c->username); + out_str(&buf, "password", c->password); + } + if (timeout > 0) + out_int(&buf, "timeout", timeout); + + ret = send_request(socket, &buf); + + strbuf_release(&buf); + return ret; +} + +static void spawn_daemon(const char *socket) +{ + struct child_process daemon; + const char *argv[] = { NULL, NULL, NULL }; + char buf[128]; + int r; + + memset(&daemon, 0, sizeof(daemon)); + argv[0] = "git-credential-cache--daemon"; + argv[1] = socket; + daemon.argv = argv; + daemon.no_stdin = 1; + daemon.out = -1; + + if (start_command(&daemon)) + die_errno("unable to start cache daemon"); + r = read_in_full(daemon.out, buf, sizeof(buf)); + if (r < 0) + die_errno("unable to read result code from cache daemon"); + if (r != 3 || memcmp(buf, "ok\n", 3)) + die("cache daemon did not start: %.*s", r, buf); + close(daemon.out); +} + +int main(int argc, const char **argv) +{ + struct credential c = { NULL }; + char *socket_path = NULL; + int timeout = 900; + struct string_list chain = STRING_LIST_INIT_NODUP; + int exit_mode = 0; + int reject_mode = 0; + const char * const usage[] = { + "git credential-cache [options]", + NULL + }; + struct option options[] = { + OPT_BOOLEAN(0, "exit", &exit_mode, + "tell a running daemon to exit"), + OPT_BOOLEAN(0, "reject", &reject_mode, + "reject a cached credential"), + OPT_INTEGER(0, "timeout", &timeout, + "number of seconds to cache credentials"), + OPT_STRING(0, "socket", &socket_path, "path", + "path of cache-daemon socket"), + OPT_STRING_LIST(0, "chain", &chain, "helper", + "use to get non-cached credentials"), + OPT_STRING(0, "username", &c.username, "name", + "an existing username"), + OPT_STRING(0, "description", &c.description, "desc", + "human-readable description of the credential"), + OPT_STRING(0, "unique", &c.unique, "token", + "a unique context for the credential"), + OPT_END() + }; + + argc = parse_options(argc, argv, NULL, options, usage, 0); + if (argc) + usage_with_options(usage, options); + /* credential_reject wants to free() these */ + if (c.username) + c.username = xstrdup(c.username); + if (c.password) + c.password = xstrdup(c.password); + + if (!socket_path) + socket_path = expand_user_path("~/.git-credential-cache/socket"); + if (!socket_path) + die("unable to find a suitable socket path; use --socket"); + + if (exit_mode) { + do_cache(socket_path, "exit", NULL, -1); + return 0; + } + + if (reject_mode) { + do_cache(socket_path, "erase", &c, -1); + credential_reject(&c, &chain); + return 0; + } + + if (do_cache(socket_path, "get", &c, -1) > 0) + return 0; + + credential_fill(&c, &chain); + printf("username=%s\n", c.username); + printf("password=%s\n", c.password); + + if (do_cache(socket_path, "store", &c, timeout) < 0) { + spawn_daemon(socket_path); + do_cache(socket_path, "store", &c, timeout); + } + return 0; +} diff --git a/git-compat-util.h b/git-compat-util.h index ddfbf77149..1dfa4c5ec2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -130,6 +130,7 @@ #include #include #include +#include #ifndef NO_INTTYPES_H #include #else diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 68d838c26d..994a0aae91 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -182,4 +182,95 @@ test_expect_success 'internal getpass can pull from config' ' EOF ' +test_expect_success 'credential-cache caches password' ' + test_when_finished "git credential-cache --exit" && + check --unique=host cache <<-\EOF && + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF + check --unique=host cache <<-\EOF + username=askpass-result + password=askpass-result + -- + EOF +' + +test_expect_success 'credential-cache requires matching unique token' ' + test_when_finished "git credential-cache --exit" && + check --unique=host cache <<-\EOF && + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF + check --unique=host2 cache <<-\EOF + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF +' + +test_expect_success 'credential-cache requires matching usernames' ' + test_when_finished "git credential-cache --exit" && + check --unique=host cache <<-\EOF && + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF + check --unique=host --username=other cache <<-\EOF + username=other + password=askpass-result + -- + askpass: Password: + EOF +' + +test_expect_success 'credential-cache times out' ' + test_when_finished "git credential-cache --exit || true" && + check --unique=host "cache --timeout=1" <<-\EOF && + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF + sleep 2 && + check --unique=host cache <<-\EOF + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF +' + +test_expect_success 'credential-cache removes rejected credentials' ' + test_when_finished "git credential-cache --exit || true" && + check --unique=host cache <<-\EOF && + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF + check --reject --unique=host --username=askpass-result cache <<-\EOF && + -- + EOF + check --unique=host cache <<-\EOF + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF +' + test_done diff --git a/unix-socket.c b/unix-socket.c new file mode 100644 index 0000000000..cf9890f57c --- /dev/null +++ b/unix-socket.c @@ -0,0 +1,58 @@ +#include "cache.h" +#include "unix-socket.h" + +static int unix_stream_socket(void) +{ + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + die_errno("unable to create socket"); + return fd; +} + +static void unix_sockaddr_init(struct sockaddr_un *sa, const char *path) +{ + int size = strlen(path) + 1; + if (size > sizeof(sa->sun_path)) + die("socket path is too long to fit in sockaddr"); + memset(sa, 0, sizeof(*sa)); + sa->sun_family = AF_UNIX; + memcpy(sa->sun_path, path, size); +} + +int unix_stream_connect(const char *path) +{ + int fd; + struct sockaddr_un sa; + + unix_sockaddr_init(&sa, path); + fd = unix_stream_socket(); + if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + close(fd); + return -1; + } + return fd; +} + +int unix_stream_listen(const char *path) +{ + int fd; + struct sockaddr_un sa; + + unix_sockaddr_init(&sa, path); + fd = unix_stream_socket(); + + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + unlink(path); + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + close(fd); + return -1; + } + } + + if (listen(fd, 5) < 0) { + close(fd); + return -1; + } + + return fd; +} diff --git a/unix-socket.h b/unix-socket.h new file mode 100644 index 0000000000..e271aeec5a --- /dev/null +++ b/unix-socket.h @@ -0,0 +1,7 @@ +#ifndef UNIX_SOCKET_H +#define UNIX_SOCKET_H + +int unix_stream_connect(const char *path); +int unix_stream_listen(const char *path); + +#endif /* UNIX_SOCKET_H */ From 3fc3ee73327b955d9759e802ca3e3d9c08429925 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:58:14 -0400 Subject: [PATCH 2073/3720] credentials: add "store" helper This is like "cache", except that we actually put the credentials on disk. This can be terribly insecure, of course, but we do what we can to protect them by filesystem permissions, and we warn the user in the documentation. This is not unlike using .netrc to store entries, but it's a little more user-friendly. Instead of putting credentials in place ahead of time, we transparently store them after prompting the user for them once. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- .gitignore | 1 + Documentation/git-credential-store.txt | 69 ++++++++++++++++++++ Documentation/gitcredentials.txt | 5 ++ Makefile | 1 + credential-store.c | 87 ++++++++++++++++++++++++++ t/t0300-credentials.sh | 55 ++++++++++++++++ 6 files changed, 218 insertions(+) create mode 100644 Documentation/git-credential-store.txt create mode 100644 credential-store.c diff --git a/.gitignore b/.gitignore index a6b0bd4035..2b7a3f9876 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ /git-count-objects /git-credential-cache /git-credential-cache--daemon +/git-credential-store /git-cvsexportcommit /git-cvsimport /git-cvsserver diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.txt new file mode 100644 index 0000000000..9fc0f764a1 --- /dev/null +++ b/Documentation/git-credential-store.txt @@ -0,0 +1,69 @@ +git-credential-store(1) +======================= + +NAME +---- +git-credential-store - helper to store credentials on disk + +SYNOPSIS +-------- +------------------- +git config credential.helper 'store [options]' +------------------- + +DESCRIPTION +----------- + +NOTE: Using this helper will store your passwords unencrypted on disk, +protected only by filesystem permissions. If this is not an acceptable +security tradeoff, try linkgit:git-credential-cache[1], or find a helper +that integrates with secure storage provided by your operating system. + +This command requests credentials from the user and stores them +indefinitely on disk for use by future git programs. + +You probably don't want to invoke this command directly; it is meant to +be used as a credential helper by other parts of git. See +linkgit:gitcredentials[7] or `EXAMPLES` below. + +OPTIONS +------- + +--store=:: + + Use `` to store credentials. The file will have its + filesystem permissions set to prevent other users on the system + from reading it, but will not be encrypted or otherwise + protected. + +--chain :: + + Specify an external helper to use for retrieving credentials + from the user, instead of the default method. The resulting + credentials are then stored as normal. This option can be + given multiple times; each chained helper will be tried until + credentials are received. + +Git may provide other options to the program when it is called as a +credential helper; see linkgit:gitcredentials[7]. + +EXAMPLES +-------- + +The point of this helper is to reduce the number of times you must type +your username or password. For example: + +------------------------------------ +$ git config credential.helper store +$ git push http://example.com/repo.git +Username: +Password: + +[several days later] +$ git push http://example.com/repo.git +[your credentials are used automatically] +------------------------------------ + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt index bd1a3b66f3..33ea56cb7d 100644 --- a/Documentation/gitcredentials.txt +++ b/Documentation/gitcredentials.txt @@ -88,6 +88,11 @@ cache:: Cache credentials in memory for a short period of time. See linkgit:git-credential-cache[1] for details. +store:: + + Store credentials indefinitely on disk. See + linkgit:git-credential-store[1] for details. + You may may also have third-party helpers installed; search for `credential-*` in the output of `git help -a`, and consult the documentation of individual helpers. Once you have selected a helper, diff --git a/Makefile b/Makefile index 442e249b08..22e2afc946 100644 --- a/Makefile +++ b/Makefile @@ -422,6 +422,7 @@ PROGRAM_OBJS += http-backend.o PROGRAM_OBJS += sh-i18n--envsubst.o PROGRAM_OBJS += credential-cache.o PROGRAM_OBJS += credential-cache--daemon.o +PROGRAM_OBJS += credential-store.o PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS)) diff --git a/credential-store.c b/credential-store.c new file mode 100644 index 0000000000..8ab858215b --- /dev/null +++ b/credential-store.c @@ -0,0 +1,87 @@ +#include "cache.h" +#include "credential.h" +#include "string-list.h" +#include "parse-options.h" + +static int lookup_credential(const char *fn, struct credential *c) +{ + config_exclusive_filename = fn; + credential_from_config(c); + return c->username && c->password; +} + +static void store_item(const char *fn, const char *unique, + const char *item, const char *value) +{ + struct strbuf key = STRBUF_INIT; + + if (!unique) + return; + + config_exclusive_filename = fn; + umask(077); + + strbuf_addf(&key, "credential.%s.%s", unique, item); + git_config_set(key.buf, value); + strbuf_release(&key); +} + +static void store_credential(const char *fn, struct credential *c) +{ + store_item(fn, c->unique, "username", c->username); + store_item(fn, c->unique, "password", c->password); +} + +static void remove_credential(const char *fn, struct credential *c) +{ + store_item(fn, c->unique, "username", NULL); + store_item(fn, c->unique, "password", NULL); +} + +int main(int argc, const char **argv) +{ + const char * const usage[] = { + "git credential-store [options]", + NULL + }; + struct credential c = { NULL }; + struct string_list chain = STRING_LIST_INIT_NODUP; + char *store = NULL; + int reject = 0; + struct option options[] = { + OPT_STRING_LIST(0, "store", &store, "file", + "fetch and store credentials in "), + OPT_STRING_LIST(0, "chain", &chain, "helper", + "use to get non-cached credentials"), + OPT_BOOLEAN(0, "reject", &reject, + "reject a stored credential"), + OPT_STRING(0, "username", &c.username, "name", + "an existing username"), + OPT_STRING(0, "description", &c.description, "desc", + "human-readable description of the credential"), + OPT_STRING(0, "unique", &c.unique, "token", + "a unique context for the credential"), + OPT_END() + }; + + argc = parse_options(argc, argv, NULL, options, usage, 0); + if (argc) + usage_with_options(usage, options); + + if (!store) + store = expand_user_path("~/.git-credentials"); + if (!store) + die("unable to set up default store; use --store"); + + if (reject) + remove_credential(store, &c); + else { + if (!lookup_credential(store, &c)) { + credential_fill(&c, &chain); + store_credential(store, &c); + } + printf("username=%s\n", c.username); + printf("password=%s\n", c.password); + } + return 0; +} diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 994a0aae91..5d5497619a 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -273,4 +273,59 @@ test_expect_success 'credential-cache removes rejected credentials' ' EOF ' +test_expect_success 'credential-store stores password' ' + test_when_finished "rm -f .git-credentials" && + check --unique=host store <<-\EOF && + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF + check --unique=host store <<-\EOF + username=askpass-result + password=askpass-result + -- + EOF +' + +test_expect_success 'credential-store requires matching unique token' ' + test_when_finished "rm -f .git-credentials" && + check --unique=host store <<-\EOF && + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF + check --unique=host2 store <<-\EOF + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF +' + +test_expect_success 'credential-store removes rejected credentials' ' + test_when_finished "rm -f .git-credentials" && + check --unique=host store <<-\EOF && + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF + check --reject --unique=host --username=askpass-result store <<-\EOF && + -- + EOF + check --unique=host store <<-\EOF + username=askpass-result + password=askpass-result + -- + askpass: Username: + askpass: Password: + EOF +' + test_done From 1e481b38ac77c9ab32a54bd419d0e60e6d5ee5d1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Jul 2011 03:58:59 -0400 Subject: [PATCH 2074/3720] credentials: add "getpass" helper This just does the normal "ask on the terminal, or use GIT_ASKPASS" logic that we already do. But it's useful for writers of third-party helpers. See the documentation for an example. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- .gitignore | 1 + Documentation/git-credential-getpass.txt | 58 ++++++++++++++++++++++++ Makefile | 1 + credential-getpass.c | 37 +++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 Documentation/git-credential-getpass.txt create mode 100644 credential-getpass.c diff --git a/.gitignore b/.gitignore index 2b7a3f9876..a26ad005ff 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ /git-credential-cache /git-credential-cache--daemon /git-credential-store +/git-credential-getpass /git-cvsexportcommit /git-cvsimport /git-cvsserver diff --git a/Documentation/git-credential-getpass.txt b/Documentation/git-credential-getpass.txt new file mode 100644 index 0000000000..a37c7a2f97 --- /dev/null +++ b/Documentation/git-credential-getpass.txt @@ -0,0 +1,58 @@ +git-credential-getpass(1) +========================= + +NAME +---- +git-credential-getpass - helper to request credentials from a user + +SYNOPSIS +-------- +[verse] +git credential-getpass + +DESCRIPTION +----------- + +This command requests credentials from the user using git's "default" +scheme, including asking via the terminal and respecting the +`GIT_ASKPASS` environment variable; see linkgit:gitcredentials[7] for a +complete description. The helpers are provided on stdout using git's +credential helper protocol. + +There is no point in using this program as a credential helper by +itself; it is exactly equivalent to git's behavior when no helper is +configured. + +However, writers of third-party helpers may want to invoke this program +to simulate git's behavior. + +EXAMPLES +-------- + +Here's a simple, silly example of a helper that stores credentials on +disk (similar to linkgit:git-credential-store[1]), and how it could use +the `getpass` helper. + +------------------------------------------- +#!/bin/sh + +STORAGE=$HOME/.credentials + +for i in "$@"; do + case "$i" in + --unique=*) + unique=${i#--unique=} ;; + esac +done + +if ! test -e "$STORAGE/$unique"; then + mkdir -m 0700 "$STORAGE" + git credential-getpass "$@" >"$STORAGE/$unique" +fi + +cat "$STORAGE/$unique" +------------------------------------------- + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index 22e2afc946..1af45895b2 100644 --- a/Makefile +++ b/Makefile @@ -423,6 +423,7 @@ PROGRAM_OBJS += sh-i18n--envsubst.o PROGRAM_OBJS += credential-cache.o PROGRAM_OBJS += credential-cache--daemon.o PROGRAM_OBJS += credential-store.o +PROGRAM_OBJS += credential-getpass.o PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS)) diff --git a/credential-getpass.c b/credential-getpass.c new file mode 100644 index 0000000000..6bfb8f8c72 --- /dev/null +++ b/credential-getpass.c @@ -0,0 +1,37 @@ +#include "cache.h" +#include "credential.h" +#include "parse-options.h" +#include "string-list.h" + +int main(int argc, const char **argv) +{ + const char * const usage[] = { + "git credential-getpass [options]", + NULL + }; + struct credential c = { NULL }; + int reject = 0; + struct option options[] = { + OPT_BOOLEAN(0, "reject", &reject, + "reject a stored credential"), + OPT_STRING(0, "username", &c.username, "name", + "an existing username"), + OPT_STRING(0, "description", &c.description, "desc", + "human-readable description of the credential"), + OPT_STRING(0, "unique", &c.unique, "token", + "a unique context for the credential"), + OPT_END() + }; + + argc = parse_options(argc, argv, NULL, options, usage, 0); + if (argc) + usage_with_options(usage, options); + + if (reject) + return 0; + + credential_getpass(&c); + printf("username=%s\n", c.username); + printf("password=%s\n", c.password); + return 0; +} From feb827175b307c2ef061cd335ad4f38e008d3db6 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 2075/3720] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index ce9dd980eb..b659c9f4ef 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,6 +14,12 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From e4faf8c2c080ded26c5141f17481bfcf57223dd0 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 2076/3720] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 65 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 0ecef9d7b0..3721817097 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index 025aa47c80..c1098bc029 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); create_object_directory(); diff --git a/cache.h b/cache.h index fcf4501a60..77d75b5564 100644 --- a/cache.h +++ b/cache.h @@ -601,6 +601,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum branch_track { BRANCH_TRACK_UNSPECIFIED = -1, BRANCH_TRACK_NEVER = 0, diff --git a/compat/mingw.c b/compat/mingw.c index 6ef0cc4f99..793aadf9ea 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,10 @@ #include #include "../strbuf.h" #include "../run-command.h" +#include "../cache.h" static const int delay[] = { 0, 1, 10, 20, 40 }; +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname) return ret; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } @@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index b659c9f4ef..78ff4c5832 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir #define WNOHANG 1 @@ -321,6 +318,9 @@ static inline char *mingw_find_last_dir_sep(const char *path) void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index e31d805eac..4db61693ce 100644 --- a/config.c +++ b/config.c @@ -663,6 +663,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 03d29e8d48..23f8ba5642 100644 --- a/environment.c +++ b/environment.c @@ -59,6 +59,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; struct startup_info *startup_info; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index ffc5130dcd..6acdf55e26 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -576,4 +576,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From d305a51c551f0130953c6dddc5c8d03e9984610a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 2077/3720] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 793aadf9ea..d4b1cafd8b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From be7ee62282dad94eba2007fe1759470cdc9afa8c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 2078/3720] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..bf7049e7d9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 2aab4f04005c34174d0cb55fbfda94385367d54b Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 2079/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index fd6a43d0a2..3c6dab147e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,9 +1269,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -2079,7 +2076,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2091,12 +2088,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2117,18 +2121,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2149,20 +2150,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 21f83697a67ff17b13223ecc71f9cd37a8a6aa6d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 2080/3720] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index e22ba5c321..d50b455dce 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -290,6 +290,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -308,6 +309,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 3c6dab147e..c5037685e3 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From d99a501ff2592a15e0a0dd82099c0003a9ce3743 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 2081/3720] Work around the command line limit on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 4cde0c493b..6b18e34726 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9480,7 +9480,19 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 95ed1aa28071663f289562838335d674788abaec Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 2082/3720] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index ad66410564..b157cb8581 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' ! test -d newdir/here ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done From 37df3f2b767a29c0c42790ba3be2df4155e51515 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 2083/3720] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index be745fb23f..30f08182b7 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' ' git config foo.bar zar && git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar" ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_i18ncmp expect actual ' @@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_i18ncmp expect actual ' @@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' From c1265c88ca2a8a45374f05b7e7862e6436cea25a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 2084/3720] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 58 ++++++++++++++++++++++++++++++++++++++-- t/t5516-fetch-push.sh | 36 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 3721817097..7a309d6c1c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1640,6 +1640,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 89e6c0f69e..561f124436 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -18,7 +18,9 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -80,7 +82,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -346,6 +353,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -377,6 +422,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -405,6 +457,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 3abb2907ea..866e5b3453 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -782,4 +782,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 1dbf742410b2ac966f0b38838671a992fdc4855e Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 2085/3720] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 98ab33aae7..f53d2ef429 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1039,7 +1039,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 36522df713b21beba084e54064375b16d3bd3ea6 Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 23 May 2010 03:00:47 -0400 Subject: [PATCH 2086/3720] send-email: handle Windows paths for display just like we do for processing In git-send-email.perl, here are two checks to determine if $smtp_server is an absolute path (so it'll be treated as a mailer) or not (so it'll be treated as a hostname). The one that handles actual mail processing has been taught to recognize Windows pathnames by commit 33b2e81f. The other check is just to tell the user what happened, so it's far less important, but the current state is that we will still claim to the user that c:/foo/bar is a server. =) This makes the second check consistent with the first. Signed-off-by: bert Dvornik --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index f53d2ef429..66f7abd6ed 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1125,7 +1125,7 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { From a32e64d6e5666118eb6d8834d01bfce013f0cf37 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 2 Jun 2010 00:41:33 +0200 Subject: [PATCH 2087/3720] Add a Windows-specific fallback to getenv("HOME"); This fixes msysGit issue 482 properly. Signed-off-by: Johannes Schindelin --- builtin/config.c | 4 ++-- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ config.c | 2 +- git-compat-util.h | 4 ++++ path.c | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/config.c b/builtin/config.c index 211e118d57..4ac4d17f4b 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_) local = config_exclusive_filename; if (!local) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); local = repo_config = git_pathdup("config"); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); + char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; diff --git a/compat/mingw.c b/compat/mingw.c index d4b1cafd8b..b0dd5b6e23 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1821,3 +1821,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } + +const char *get_windows_home_directory() +{ + static const char *home_directory = NULL; + struct strbuf buf = STRBUF_INIT; + + if (home_directory) + return home_directory; + + home_directory = getenv("HOME"); + if (home_directory && *home_directory) + return home_directory; + + strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); + home_directory = strbuf_detach(&buf, NULL); + + return home_directory; +} diff --git a/compat/mingw.h b/compat/mingw.h index 78ff4c5832..3078f39678 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -352,3 +352,6 @@ static int mingw_main(c,v) * Used by Pthread API implementation for Windows */ extern int err_win_to_posix(DWORD winerr); + +extern const char *get_windows_home_directory(); +#define get_home_directory() get_windows_home_directory() diff --git a/config.c b/config.c index 4db61693ce..1f4b703a6b 100644 --- a/config.c +++ b/config.c @@ -873,7 +873,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - home = getenv("HOME"); + home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) { diff --git a/git-compat-util.h b/git-compat-util.h index 6acdf55e26..bc0848d4e3 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -580,4 +580,8 @@ int remove_or_warn(unsigned int mode, const char *path); #define mark_as_git_dir(x) /* noop */ #endif +#ifndef get_home_directory +#define get_home_directory() getenv("HOME") +#endif + #endif diff --git a/path.c b/path.c index 4d73cc9cd2..39b576c298 100644 --- a/path.c +++ b/path.c @@ -240,7 +240,7 @@ char *expand_user_path(const char *path) const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { - const char *home = getenv("HOME"); + const char *home = get_home_directory(); if (!home) goto return_null; strbuf_add(&user_path, home, strlen(home)); From e058239f27439fcc714dbd58dbab370a86e8bf8e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 12 Jun 2010 00:44:01 +0200 Subject: [PATCH 2088/3720] t7602: cope with CR/LF The output of git-merge-octopus has CR/LF line endings, so let's just strip the CR out. Signed-off-by: Johannes Schindelin --- t/t7602-merge-octopus-many.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 0a46795ae7..b02658bf77 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -65,7 +65,8 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && - git merge c2 c3 c4 >actual && + git merge c2 c3 c4 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -79,7 +80,8 @@ Merge made by octopus. EOF test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && + git merge c4 c5 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' @@ -96,7 +98,8 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && - git merge c1 c2 >actual && + git merge c1 c2 >actual.raw && + tr -d "\r" < actual.raw > actual && test_cmp actual expected ' From d132e8bef46b8dfcc7edf1e1fa71e6af377109c3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 May 2010 21:50:11 +0200 Subject: [PATCH 2089/3720] git am: ignore dirty submodules This fixes a rebase in the presence of dirty submodules. This is orthogonal to the application of patches changing submodules. Signed-off-by: Johannes Schindelin --- git-am.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/git-am.sh b/git-am.sh index 8d185aa2d6..2d96e4a3da 100755 --- a/git-am.sh +++ b/git-am.sh @@ -518,7 +518,8 @@ case "$resolved" in '') files=$(git ls-files) ;; ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; + files=$(git diff-index --ignore-submodules --cached \ + --name-only HEAD --) ;; esac || exit if test "$files" then @@ -687,7 +688,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec case "$resolved$interactive" in tt) # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" + git diff-index --ignore-submodules -p --cached \ + HEAD -- >"$dotest/patch" ;; esac esac @@ -763,7 +765,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."; ec # trust what the user has in the index file and the # working tree. resolved= - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached HEAD -- && { gettext "No changes - did you forget to use 'git add'? If there is nothing left to stage, chances are that something else already introduced the same changes; you might want to skip this patch."; echo @@ -787,7 +789,8 @@ did you forget to use 'git add'?"; echo then # Applying the patch to an earlier tree and merging the # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { + git diff-index --ignore-submodules --quiet --cached \ + HEAD -- && { say "$(gettext "No changes -- Patch already applied.")" go_next continue From a9dd8c24954b6674a083abc5f67c8d1635e25d12 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Wed, 16 Jun 2010 20:11:00 +0200 Subject: [PATCH 2090/3720] work around misdetection of stdin attached to a tty Git on Windows was made aware of the fact that sometimes a file may be used by another process and so an operation may fail but the user might be able to fix it and is asking for confirmation whether it should retry. This is implemented in a way that git only asks in case stdin and stderr are attached to a tty. Unfortunately this seems to be misdetected sometimes causing the testsuite to hang when git is waiting for a user answer. This patch works around the situation. Signed-off-by: Heiko Voigt --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index df25f17929..e86f9ec67a 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# for git on windows so stdin will not be misdetected as attached to a +# terminal +exec < /dev/null + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in From 7e0a658f15399555b13535fc06823a2ec7729402 Mon Sep 17 00:00:00 2001 From: Cezary Zawadka Date: Tue, 13 Jul 2010 16:17:43 +0200 Subject: [PATCH 2091/3720] Allow using UNC path for git repository [efl: moved MinGW-specific part to compat/] [jes: fixed compilation on non-Windows] Signed-off-by: Cezary Zawadka Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- cache.h | 1 - compat/mingw.c | 23 +++++++++++++++++++++++ compat/mingw.h | 2 ++ git-compat-util.h | 4 ++++ path.c | 7 ------- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cache.h b/cache.h index 77d75b5564..0242563906 100644 --- a/cache.h +++ b/cache.h @@ -754,7 +754,6 @@ int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); -int offset_1st_component(const char *path); /* object replacement */ #define READ_SHA1_FILE_REPLACE 1 diff --git a/compat/mingw.c b/compat/mingw.c index b0dd5b6e23..3bc06888c3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1839,3 +1839,26 @@ const char *get_windows_home_directory() return home_directory; } + +int mingw_offset_1st_component(const char *path) +{ + if (has_dos_drive_prefix(path)) + return 2 + is_dir_sep(path[2]); + + /* unc paths */ + if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + + /* skip server name */ + char *pos = strpbrk(path + 2, "\\/"); + if (!pos) + return 0; + + do { + pos++; + } while (*pos && !is_dir_sep(*pos)); + + return pos - path; + } + + return is_dir_sep(path[0]); +} diff --git a/compat/mingw.h b/compat/mingw.h index 3078f39678..ee3104b6a9 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -312,6 +312,8 @@ static inline char *mingw_find_last_dir_sep(const char *path) return ret; } #define find_last_dir_sep mingw_find_last_dir_sep +int mingw_offset_1st_component(const char *path); +#define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index bc0848d4e3..9c4c6e4672 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -212,6 +212,10 @@ extern char *gitbasename(char *); #define has_dos_drive_prefix(path) 0 #endif +#ifndef offset_1st_component +#define offset_1st_component(path) (is_dir_sep((path)[0])) +#endif + #ifndef is_dir_sep #define is_dir_sep(c) ((c) == '/') #endif diff --git a/path.c b/path.c index 39b576c298..8745aad206 100644 --- a/path.c +++ b/path.c @@ -655,10 +655,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} From 22afe73f419d238de53d5ee737f90be2b25d6fcc Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Tue, 13 Jul 2010 16:23:58 +0200 Subject: [PATCH 2092/3720] config.c: trivial fix for compile-time warning The warning ("builtin/config.c:351: warning: initialization discards qualifiers from pointer target type") was introduced in commit 6754497c. Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- builtin/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/config.c b/builtin/config.c index 4ac4d17f4b..9ac3b9ec69 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -361,7 +361,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = get_home_directory(); + const char *home = get_home_directory(); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; From 0ef905871fedb1fc3f82969df6652385c7b5380d Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 13 Jul 2010 12:19:52 -0400 Subject: [PATCH 2093/3720] Make mingw_offset_1st_component() behave consistently for all paths. mingw_offset_1st_component() returns "foo" for inputs "/foo" and "c:/foo", but inconsistently returns "/foo" for UNC input "/machine/share/foo". Fix it to return "foo" for all cases. Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0 Signed-off-by: Eric Sunshine Signed-off-by: Johannes Schindelin --- compat/mingw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3bc06888c3..3825e3aa68 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1842,23 +1842,24 @@ const char *get_windows_home_directory() int mingw_offset_1st_component(const char *path) { + int offset = 0; if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); + offset = 2; /* unc paths */ - if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { + else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { /* skip server name */ char *pos = strpbrk(path + 2, "\\/"); if (!pos) - return 0; + return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - return pos - path; + offset = pos - path; } - return is_dir_sep(path[0]); + return offset + is_dir_sep(path[offset]); } From 9a52fc2f7e038f7c8fd58036680ae4628c22d019 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Jul 2010 18:06:05 +0200 Subject: [PATCH 2094/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not set yet Signed-off-by: Johannes Schindelin --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index c5037685e3..0d5bd3465f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [gitexec git-gui--askpass] +} if {![info exists env(GIT_ASK_YESNO)]} { set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] } From 54598de391a4806363b75b6a78b7a7d72844b031 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 26 Jul 2010 00:36:19 +0100 Subject: [PATCH 2095/3720] Fix another invocation of git from gitk with an overly long command-line Signed-off-by: Sebastian Schuberth --- gitk-git/gitk | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 6b18e34726..2a92e20f06 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -369,7 +369,7 @@ proc start_rev_list {view} { if {$revs eq {}} { return 0 } - set args [concat $vflags($view) $revs] + set args [limit_arg_length [concat $vflags($view) $revs]] } else { set args $vorigargs($view) } @@ -9480,18 +9480,7 @@ proc getallcommits {} { } } if {$ids ne {}} { - set cmd [concat $cmd $ids] - # The maximum command line length for the CreateProcess function is 32767 characters, see - # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx - # Be a little conservative in case Tcl adds some more stuff to the command line we do not - # know about and truncate the command line at a SHA1-boundary below 32000 characters. - if {[tk windowingsystem] == "win32" && - [string length $cmd] > 32000} { - set ndx [string last " " $cmd 32000] - if {$ndx != -1} { - set cmd [string range $cmd 0 $ndx] - } - } + set cmd [limit_arg_length [concat $cmd $ids]] set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits @@ -9502,6 +9491,21 @@ proc getallcommits {} { } } +# The maximum command line length for the CreateProcess function is 32767 characters, see +# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx +# Be a little conservative in case Tcl adds some more stuff to the command line we do not +# know about and truncate the command line at a SHA1-boundary below 32000 characters. +proc limit_arg_length {cmd} { + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + return [string range $cmd 0 $ndx] + } + } + return $cmd +} + # Since most commits have 1 parent and 1 child, we group strings of # such commits into "arcs" joining branch/merge points (BMPs), which # are commits that either don't have 1 parent or don't have 1 child. From 222718b7591578a4873d86babd23a11b0e1a95f5 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:00 +0000 Subject: [PATCH 2096/3720] Enable color output in Windows cmd.exe Git requires the TERM environment variable to be set for all color* settings. Simulate the TERM variable if it is not set (default on Windows). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 3825e3aa68..83f06f6e74 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name) if (!result) result = getenv_cs("TEMP"); } + else if (!result && !strcmp(name, "TERM")) { + /* simulate TERM to enable auto-color (see color.c) */ + result = "winansi"; + } return result; } From 26a4dca293580f0dce2c7977cf76c08ce1eb0b19 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:01 +0000 Subject: [PATCH 2097/3720] Support Unicode console output on Windows WriteConsoleW seems to be the only way to reliably print unicode to the console (without weird code page conversions). Also redirects vfprintf to the winansi.c version. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ compat/winansi.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index ee3104b6a9..01ce671ab2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -293,9 +293,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); int winansi_fputs(const char *str, FILE *stream); int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int winansi_vfprintf(FILE *stream, const char *format, va_list list); #define fputs winansi_fputs #define printf(...) winansi_printf(__VA_ARGS__) #define fprintf(...) winansi_fprintf(__VA_ARGS__) +#define vfprintf winansi_vfprintf /* * git specific compatibility diff --git a/compat/winansi.c b/compat/winansi.c index dedce2104e..abe0feaa2c 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -3,6 +3,7 @@ */ #include "../git-compat-util.h" +#include /* Functions to be wrapped: @@ -10,6 +11,7 @@ #undef printf #undef fprintf #undef fputs +#undef vfprintf /* TODO: write */ /* @@ -46,6 +48,18 @@ static void init(void) initialized = 1; } +static int write_console(const char *str, size_t len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) @@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream) int rv = 0; const char *pos = str; + fflush(stream); + while (*pos) { pos = strstr(str, "\033["); if (pos) { size_t len = pos - str; if (len) { - size_t out_len = fwrite(str, 1, len, stream); + size_t out_len = write_console(str, len); rv += out_len; if (out_len < len) return rv; @@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream) str = pos + 2; rv += 2; - fflush(stream); - pos = set_attr(str); rv += pos - str; str = pos; } else { - rv += strlen(str); - fputs(str, stream); + size_t len = strlen(str); + rv += write_console(str, len); return rv; } } @@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream) return EOF; } -static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +int winansi_vfprintf(FILE *stream, const char *format, va_list list) { int len, rv; char small_buf[256]; From cc6c838d8a829ee3a52721df6483cb22fa9c89cb Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:02 +0000 Subject: [PATCH 2098/3720] Detect console streams more reliably on Windows GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is redirected. Use _get_osfhandle of the FILE* instead. _isatty() is true for all character devices (including parallel and serial ports). Check return value of GetConsoleScreenBufferInfo instead to reliably detect console handles (also don't initialize internal state from an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function fails). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index abe0feaa2c..c4be401a6e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -25,27 +25,39 @@ static HANDLE console; static WORD plain_attr; static WORD attr; static int negative; +static FILE *last_stream = NULL; -static void init(void) +static int is_console(FILE *stream) { CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE hcon; static int initialized = 0; - if (initialized) - return; - console = GetStdHandle(STD_OUTPUT_HANDLE); - if (console == INVALID_HANDLE_VALUE) - console = NULL; + /* use cached value if stream hasn't changed */ + if (stream == last_stream) + return console != NULL; - if (!console) - return; + last_stream = stream; + console = NULL; - GetConsoleScreenBufferInfo(console, &sbi); - attr = plain_attr = sbi.wAttributes; - negative = 0; + /* get OS handle of the stream */ + hcon = (HANDLE) _get_osfhandle(_fileno(stream)); + if (hcon == INVALID_HANDLE_VALUE) + return 0; - initialized = 1; + /* check if its a handle to a console output screen buffer */ + if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + return 0; + + if (!initialized) { + attr = plain_attr = sbi.wAttributes; + negative = 0; + initialized = 1; + } + + console = hcon; + return 1; } static int write_console(const char *str, size_t len) @@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream) { int rv; - if (!isatty(fileno(stream))) - return fputs(str, stream); - - init(); - - if (!console) + if (!is_console(stream)) return fputs(str, stream); rv = ansi_emulate(str, stream); @@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) char *buf = small_buf; va_list cp; - if (!isatty(fileno(stream))) - goto abort; - - init(); - - if (!console) + if (!is_console(stream)) goto abort; va_copy(cp, list); From e74731fdf35e3f8fdaa304437cbddb9dcf9680de Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 31 Jul 2010 00:04:03 +0000 Subject: [PATCH 2099/3720] Warn if the Windows console font doesn't support Unicode Unicode console output won't display correctly with default settings because the default console font ("Terminal") only supports the system's OEM charset. Unfortunately, this is a user specific setting, so it cannot be easily fixed by e.g. some registry tricks in the setup program. This change prints a warning on exit if console output contained non-ascii characters and the console font is supposedly not a TrueType font (which usually have decent Unicode support). Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/compat/winansi.c b/compat/winansi.c index c4be401a6e..a5ca2d9be3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #include "../git-compat-util.h" #include +#include +#include /* Functions to be wrapped: @@ -26,6 +28,54 @@ static WORD plain_attr; static WORD attr; static int negative; static FILE *last_stream = NULL; +static int non_ascii_used = 0; + +typedef struct _CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; + +typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, + PCONSOLE_FONT_INFOEX); + +static void warn_if_raster_font(void) +{ + DWORD fontFamily = 0; + PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx; + + /* don't bother if output was ascii only */ + if (!non_ascii_used) + return; + + /* GetCurrentConsoleFontEx is available since Vista */ + pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetCurrentConsoleFontEx"); + if (pGetCurrentConsoleFontEx) { + CONSOLE_FONT_INFOEX cfi; + cfi.cbSize = sizeof(cfi); + if (pGetCurrentConsoleFontEx(console, 0, &cfi)) + fontFamily = cfi.FontFamily; + } else { + /* pre-Vista: check default console font in registry */ + HKEY hkey; + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_READ, &hkey)) { + DWORD size = sizeof(fontFamily); + RegQueryValueExA(hkey, "FontFamily", NULL, NULL, + (LPVOID) &fontFamily, &size); + RegCloseKey(hkey); + } + } + + if (!(fontFamily & TMPF_TRUETYPE)) + warning("Your console font probably doesn\'t support " + "Unicode. If you experience strange characters in the output, " + "consider switching to a TrueType font such as Lucida Console!"); +} static int is_console(FILE *stream) { @@ -54,6 +104,8 @@ static int is_console(FILE *stream) attr = plain_attr = sbi.wAttributes; negative = 0; initialized = 1; + /* check console font on exit */ + atexit(warn_if_raster_font); } console = hcon; @@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len) WriteConsoleW(console, wbuf, wlen, NULL, NULL); + /* remember if non-ascii characters are printed */ + if (wlen != len) + non_ascii_used = 1; + /* return original (utf-8 encoded) length */ return len; } From ea1b139becab6f35c8aec6b7e9a6f63a653b49e3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Aug 2010 21:01:08 +0200 Subject: [PATCH 2100/3720] Give commit message reencoding for output on MinGW a chance Signed-off-by: Johannes Schindelin --- log-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-tree.c b/log-tree.c index e9457019d5..c0afd976d9 100644 --- a/log-tree.c +++ b/log-tree.c @@ -509,7 +509,8 @@ void show_log(struct rev_info *opt) if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else - fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); + /* Do not use fwrite() to give MinGW reencoding a chance */ + printf("%.*s", (int)msgbuf.len, msgbuf.buf); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); From 05cd5e0a429bb13f10e819d8f3aa2b83db603d83 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 14:43:00 +0200 Subject: [PATCH 2101/3720] gitweb: Allow line number toggling with Javascript Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 70a576a626..3a95e3dcb6 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4256,6 +4256,25 @@ sub git_print_page_path { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); + print '     + + +'; } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), From 3cbf9d12183f0dd46f708be0d9faca42556f6bb2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Sep 2010 16:58:16 +0200 Subject: [PATCH 2102/3720] Gitweb: make line number toggling work for Firefox and Safari Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 3a95e3dcb6..86b17255dc 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4271,7 +4271,9 @@ function toggleLineNumbers() { e2.innerHTML = "[Hide line numbers]"; } } -document.getElementsByTagName("head")[0].innerHTML += ""; +var style = document.createElement("style"); +style.setAttribute("id", "lineNoStyle"); +document.getElementsByTagName("head")[0].appendChild(style); toggleLineNumbers(); '; From 52611f3916489126c76f3f0b06bd22d5dea9aab4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 2103/3720] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Since system_path() considers paths starting with '/' as absolute, we have to convince it to make a Windows path by stripping the leading slash. Signed-off-by: Johannes Schindelin --- http.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 0d96f37c1e..12987ad416 100644 --- a/http.c +++ b/http.c @@ -4,6 +4,7 @@ #include "run-command.h" #include "url.h" #include "credential.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -140,6 +141,18 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; +#ifdef __MINGW32__ + if (**result == '/') + *result = system_path((*result) + 1); +#endif + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -147,17 +160,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 6ab0b4bc450dcde3fee798e33a67af27c3cab561 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 07:56:21 -0700 Subject: [PATCH 2104/3720] add -e: ignore dirty submodules We cannot add untracked/modified files in submodules anyway. Signed-off-by: Johannes Schindelin --- builtin/add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/add.c b/builtin/add.c index c59b0c98fe..68fd050e94 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0644); if (out < 0) die (_("Could not open '%s' for writing."), file); From e57a26797da2e7bdaf6df2ee5d2459e98048f188 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 23 Oct 2010 08:06:23 -0700 Subject: [PATCH 2105/3720] Let deny.currentBranch=updateInstead ignore submodules They are not affected by the update anyway. Signed-off-by: Johannes Schindelin --- builtin/receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 561f124436..df38bd92a6 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -356,7 +356,7 @@ static void refuse_unconfigured_deny_delete_current(void) static void merge_worktree(unsigned char *sha1) { const char *update_refresh[] = { - "update-index", "--refresh", NULL + "update-index", "--ignore-submodules", "--refresh", NULL }; const char *read_tree[] = { "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL From d3c4ea9ecf25ceed016f905081a6e9c142c6a2e8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2010 16:10:43 +0100 Subject: [PATCH 2106/3720] grep -I: do not bother to read known-binary files Incidentally, this makes grep -I respect the "binary" attribute (actually, the "-text" attribute, but "binary" implies that). Since the attributes are not thread-safe, we now need to switch off threading if -I was passed. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 1851797540..44f66a522f 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,6 +18,7 @@ #include "quote.h" #include "dir.h" #include "thread-utils.h" +#include "attr.h" static char const * const grep_usage[] = { "git grep [options] [-e] [...] [[--] ...]", @@ -187,6 +188,22 @@ static void work_done(struct work_item *w) grep_unlock(); } +static int skip_binary(struct grep_opt *opt, const char *filename) +{ + if ((opt->binary & GREP_BINARY_NOMATCH)) { + static struct git_attr *attr_text; + struct git_attr_check check; + + if (!attr_text) + attr_text = git_attr("text"); + memset(&check, 0, sizeof(check)); + check.attr = attr_text; + return !git_checkattr(filename, 1, &check) && + ATTR_FALSE(check.value); + } + return 0; +} + static void *run(void *arg) { int hit = 0; @@ -197,6 +214,9 @@ static void *run(void *arg) if (!w) break; + if (skip_binary(opt, (const char *)w->identifier)) + continue; + opt->output_priv = w; if (w->type == WORK_SHA1) { unsigned long sz; @@ -514,6 +534,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int continue; if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; + if (skip_binary(opt, ce->name)) + continue; + /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use @@ -971,6 +994,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) string_list_append(&path_list, show_in_pager); use_threads = 0; } + if ((opt.binary & GREP_BINARY_NOMATCH)) + use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); From 4b9f0baf089992a450f09b4739856906b51312d8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 12 Jan 2009 13:20:53 +0100 Subject: [PATCH 2107/3720] Make CFLAGS more strict This is a gcc-ism, but as we use gcc exclusively, we can use them. Taken from one of Junio's mails. (Reminded to cherry-pick this patch by one of Karsten Blees' mails.) Signed-off-by: Johannes Schindelin --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 996b8fe319..9a691426ee 100644 --- a/Makefile +++ b/Makefile @@ -278,7 +278,10 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -O2 -Wall +CFLAGS = -g -O2 -Wall -Werror \ + -Wno-pointer-to-int-cast \ + -Wold-style-definition \ + -Wdeclaration-after-statement LDFLAGS = ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) From 013f1c9d36299432b546a2e6fa3a33e3211accee Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:46:41 +0100 Subject: [PATCH 2108/3720] Fix old-style function declaration Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 83f06f6e74..d4d3fdfb2e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1826,7 +1826,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) return -1; } -const char *get_windows_home_directory() +const char *get_windows_home_directory(void) { static const char *home_directory = NULL; struct strbuf buf = STRBUF_INIT; From da5d283e460b65fdc899fa42bf241ddb9b62ee52 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 01:47:45 +0100 Subject: [PATCH 2109/3720] Do not compile compat/**/*.c with -Wold-style-definition Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9a691426ee..e970f0b606 100644 --- a/Makefile +++ b/Makefile @@ -1930,7 +1930,7 @@ endif ASM_SRC := $(wildcard $(OBJECTS:o=S)) ASM_OBJ := $(ASM_SRC:S=o) -C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS)) +C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS))) .SUFFIXES: @@ -1970,6 +1970,8 @@ endif ifndef CHECK_HEADER_DEPENDENCIES $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< +$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) + $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $< $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $< endif From e1d282844b3722a6384f3fba13ed5b0537d64db6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 8 Jan 2011 17:02:17 +0100 Subject: [PATCH 2110/3720] Handle new t1501 test case properly with MinGW Signed-off-by: Johannes Schindelin --- t/t1501-worktree.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index 63849836c8..2ef2ec912e 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file ' +test_have_prereq MINGW && +# make sure to test DOS path on Windows +TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)" + test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && From fd35f56f310f8715d364236b49912666ccc8eb67 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Feb 2011 00:17:24 -0600 Subject: [PATCH 2111/3720] git grep -O -i: if the pager is 'less', pass the '-i' option Signed-off-by: Johannes Schindelin --- builtin/grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index 44f66a522f..2b6a6e357b 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1059,6 +1059,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; + if (!strcmp("less", pager)) + string_list_append(&path_list, "-i"); + if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", From 5e56c41a34f2509f567f15a0dcdacc0d0bb55f6b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Feb 2011 16:09:10 +0100 Subject: [PATCH 2112/3720] Amend "git grep -O -i: if the pager is 'less', pass the '-i' option" This change was left in the stash, for some reason. Squash this in with the next rebasing merge. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/grep.c b/builtin/grep.c index 2b6a6e357b..2fdd3faad9 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1059,7 +1059,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; - if (!strcmp("less", pager)) + if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { From 66ca34e3836006d22fa521c4850314412d468a54 Mon Sep 17 00:00:00 2001 From: Gregor Uhlenheuer Date: Fri, 18 Feb 2011 11:42:12 +0100 Subject: [PATCH 2113/3720] Git.pm: Use stream-like writing in cat_blob() This commit fixes the issue with the handling of large files causing an 'Out of memory' perl exception. Instead of reading and writing the whole blob at once now the blob is written in small pieces. The problem was raised and discussed in this mail to the msysGit mailing list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080 Signed-off-by: Gregor Uhlenheuer Signed-off-by: Johannes Schindelin --- perl/Git.pm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index a86ab709c2..0b53566ea3 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -896,22 +896,26 @@ sub cat_blob { } my $size = $1; - - my $blob; my $bytesRead = 0; while (1) { + my $blob; my $bytesLeft = $size - $bytesRead; last unless $bytesLeft; my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024; - my $read = read($in, $blob, $bytesToRead, $bytesRead); + my $read = read($in, $blob, $bytesToRead); unless (defined($read)) { $self->_close_cat_blob(); throw Error::Simple("in pipe went bad"); } $bytesRead += $read; + + unless (print $fh $blob) { + $self->_close_cat_blob(); + throw Error::Simple("couldn't write to passed in filehandle"); + } } # Skip past the trailing newline. @@ -926,11 +930,6 @@ sub cat_blob { throw Error::Simple("didn't find newline after blob"); } - unless (print $fh $blob) { - $self->_close_cat_blob(); - throw Error::Simple("couldn't write to passed in filehandle"); - } - return $size; } From ae59ceb2bd93a55044d0069a6ecd4d04fec87310 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 2114/3720] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index d4d3fdfb2e..b8928575d7 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -291,7 +291,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 2f97be0f2cc20a5eb4bc3984a9fc548a010bbb54 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 09:29:35 +0200 Subject: [PATCH 2115/3720] MinGW: Skip test redirecting to fd 4 ... because that does not work in MinGW. Signed-off-by: Johannes Schindelin --- t/t0081-line-buffer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index bd83ed371a..25dba008f3 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' ' test_cmp expect actual ' -test_expect_success 'read from file descriptor' ' +test_expect_success NOT_MINGW 'read from file descriptor' ' rm -f input && echo hello >expect && echo hello >input && From 8117ed6a2205c17823910749cf0391ad811bdfa9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Apr 2011 16:44:45 +0200 Subject: [PATCH 2116/3720] Disable test on MinGW that challenges its bash quoting Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0d0222ea2a..fae1200255 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -915,7 +915,10 @@ test_expect_success 'remote set-url --add bbb' ' ' test_expect_success 'remote set-url --delete .*' ' - test_must_fail git remote set-url --delete someremote .\* && + if test_have_prereq NOT_MINGW + then + test_must_fail git remote set-url --delete someremote .\* + fi && echo "YYY" >expect && echo baz >>expect && echo bbb >>expect && From a368f5c07eef259aa89011b1c97d4c995d9894a4 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Tue, 26 Apr 2011 10:39:30 +0100 Subject: [PATCH 2117/3720] t3102: Windows filesystems may not use a literal asterisk in filenames. Exclude these tests when using MINGW. Signed-off-by: Pat Thoyts --- t/t3102-ls-tree-wildcards.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh index c286854485..766af3de9b 100755 --- a/t/t3102-ls-tree-wildcards.sh +++ b/t/t3102-ls-tree-wildcards.sh @@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs' . ./test-lib.sh -test_expect_success 'setup' ' +test_expect_success NOT_MINGW 'setup' ' mkdir a aa "a[a]" && touch a/one aa/two "a[a]/three" && git add a/one aa/two "a[a]/three" && git commit -m test ' -test_expect_success 'ls-tree a[a] matches literally' ' +test_expect_success NOT_MINGW 'ls-tree a* matches literally' ' cat >expected < Date: Wed, 27 Apr 2011 18:38:04 +0200 Subject: [PATCH 2118/3720] submodule: Use cat instead of echo to avoid DOS line-endings In msysGit, echo used in scripts outputs DOS line-endings while built-ins use Unix line-endings in their output. This causes t7508-status to fail due to mixed line endings in the output of git status (which calls git-submodule). Signed-off-by: Sebastian Schuberth --- git-submodule.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index f46862f61b..0c43896cb6 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -791,12 +791,16 @@ cmd_summary() { done | if test -n "$for_status"; then if [ -n "$files" ]; then - gettext "# Submodules changed but not updated:"; echo + status_msg="$(gettext "# Submodules changed but not updated:")" else - gettext "# Submodule changes to be committed:"; echo + status_msg="$(gettext "# Submodule changes to be committed:")" fi - echo "#" - sed -e 's|^|# |' -e 's|^# $|#|' + status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|') + cat < Date: Sun, 1 May 2011 14:47:09 +0100 Subject: [PATCH 2119/3720] t5407: Fix line-ending dependency in post-rewrite.args On msysGit creating the post-rewrite.args file using 'echo' has different line endings from the expected comparison. Using perl normalizes the line endings for each generated file. Signed-off-by: Pat Thoyts --- t/t5407-post-rewrite-hook.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index baa670cea5..35403b435e 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -20,9 +20,13 @@ test_expect_success 'setup' ' mkdir .git/hooks cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args -cat > "$TRASH_DIRECTORY"/post-rewrite.data +#!/usr/bin/perl +open (AR, ">$TRASH_DIRECTORY/post-rewrite.args"); +print AR \$_,"\n" foreach @ARGV; +open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data"); +while() { + print DAT; +} EOF chmod u+x .git/hooks/post-rewrite From 40d0f97f302459b31d0831e334f949f6d9801f9a Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Thu, 28 Apr 2011 00:30:49 +0200 Subject: [PATCH 2120/3720] submodule: Fix t7400, t7405, t7406 for msysGit Again, avoid using echo (which issues DOS line endings on msysGit) to not mix with Unix line-endings issued by git built-ins, even if this is at the cost of calling an external executable (cat) instead of a shell built-in (echo). --- git-sh-setup.sh | 4 +++- git-submodule.sh | 11 +++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 8e427dab31..f159380066 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -55,7 +55,9 @@ GIT_QUIET= say () { if test -z "$GIT_QUIET" then - printf '%s\n' "$*" + cat < /dev/null 2>&1 then - ( - eval_gettext "The following path is ignored by one of your .gitignore files: -\$path -Use -f if you really want to add it." && - echo - ) >&2 + cat >&2 < Date: Wed, 15 Jun 2011 16:57:59 +0200 Subject: [PATCH 2121/3720] Revert "MinGW: Add missing file mode bit defines" This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a. --- compat/mingw.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 01ce671ab2..ef5226c7c4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,12 +14,6 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 -#ifndef _STAT_H_ -#define S_IRUSR 0 -#define S_IWUSR 0 -#define S_IXUSR 0 -#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) -#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 From b7e9acf930164f3410d42b7abb7f2dc6440e2b24 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:34:33 +0100 Subject: [PATCH 2122/3720] Win32 dirent: remove unused dirent.d_ino member There are no proper inodes on Windows, so remove dirent.d_ino and #define NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in fsck.c). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- Makefile | 2 ++ compat/win32/dirent.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e970f0b606..6d67e444de 100644 --- a/Makefile +++ b/Makefile @@ -1121,6 +1121,7 @@ ifeq ($(uname_S),Windows) BLK_SHA1 = YesPlease NO_POSIX_GOODIES = UnfortunatelyYes NATIVE_CRLF = YesPlease + NO_D_INO_IN_DIRENT = YesPlease CC = compat/vcbuild/scripts/clink.pl AR = compat/vcbuild/scripts/lib.pl @@ -1212,6 +1213,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_INET_PTON = YesPlease NO_INET_NTOP = YesPlease NO_POSIX_GOODIES = UnfortunatelyYes + NO_D_INO_IN_DIRENT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/winansi.o \ diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h index 927a25ca76..b38973b051 100644 --- a/compat/win32/dirent.h +++ b/compat/win32/dirent.h @@ -9,7 +9,6 @@ typedef struct DIR DIR; #define DT_LNK 3 struct dirent { - long d_ino; /* Always zero. */ char d_name[FILENAME_MAX]; /* File name. */ union { unsigned short d_reclen; /* Always zero. */ From 89ab2f2ed2d00e6ae78d716f9dd5c98866694023 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:38:25 +0100 Subject: [PATCH 2123/3720] Win32 dirent: remove unused dirent.d_reclen member Remove the union around dirent.d_type and the unused dirent.d_reclen member (which was necessary for compatibility with the MinGW dirent runtime, which is no longer used). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/win32/dirent.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h index b38973b051..7f4e6c71d9 100644 --- a/compat/win32/dirent.h +++ b/compat/win32/dirent.h @@ -10,10 +10,7 @@ typedef struct DIR DIR; struct dirent { char d_name[FILENAME_MAX]; /* File name. */ - union { - unsigned short d_reclen; /* Always zero. */ - unsigned char d_type; /* Reimplementation adds this */ - }; + unsigned char d_type; /* file type to prevent lstat after readdir */ }; DIR *opendir(const char *dirname); From a9a0b0493b20057816f3db148067f355a73eea67 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:43:14 +0100 Subject: [PATCH 2124/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is used throughout the other Win32 code in Git, and also defines the length of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName, from which we're copying the dirent data). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/win32/dirent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h index 7f4e6c71d9..8838cd61fc 100644 --- a/compat/win32/dirent.h +++ b/compat/win32/dirent.h @@ -9,8 +9,8 @@ typedef struct DIR DIR; #define DT_LNK 3 struct dirent { - char d_name[FILENAME_MAX]; /* File name. */ unsigned char d_type; /* file type to prevent lstat after readdir */ + char d_name[MAX_PATH]; /* file name */ }; DIR *opendir(const char *dirname); From 6eae83ef75779d0f0b9b44c0ef73c5366f583451 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:47:41 +0100 Subject: [PATCH 2125/3720] Win32 dirent: clarify #include directives Git-compat-util.h is two dirs up, and already includes (which is the same as "dirent.h" due to -Icompat/win32 in the Makefile). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/win32/dirent.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c index 7a0debe51b..fac7f25047 100644 --- a/compat/win32/dirent.c +++ b/compat/win32/dirent.c @@ -1,5 +1,4 @@ -#include "../git-compat-util.h" -#include "dirent.h" +#include "../../git-compat-util.h" struct DIR { struct dirent dd_dir; /* includes d_type */ From abf8ef79aaca4945f75d97b42691f3ae2bbc7ef2 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 17:57:02 +0100 Subject: [PATCH 2126/3720] Win32 dirent: improve dirent implementation Improve the dirent implementation by removing the relics that were once necessary to plug into the now unused MinGW runtime, in preparation for Unicode file name support. Move FindFirstFile to opendir, and FindClose to closedir, with the following implications: - DIR.dd_name is no longer needed - chdir(one); opendir(relative); chdir(two); readdir() works as expected (i.e. lists one/relative instead of two/relative) - DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct - thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0 have been removed - the special case that the directory has been fully read (which was previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE && dd_stat != 0) is now handled implicitly by the FindNextFile error handling code (if a client continues to call readdir after receiving NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to the same effect) - extracting dirent data from WIN32_FIND_DATA is needed in two places, so moved to its own method - GetFileAttributes is no longer needed. The same information can be obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if the name is NOT a directory (-> ENOTDIR), otherwise we can use err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this probably breaks other functionality. Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was fortunately a NOOP (searching for '*' always finds '.' and '..'), otherwise the subsequent code would have copied data from an uninitialized buffer). Changes malloc to git support function xmalloc, so opendir will die() if out of memory, rather than failing with ENOMEM and letting git work on incomplete directory listings (error handling in dir.c is quite sparse). Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/win32/dirent.c | 111 ++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 58 deletions(-) diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c index fac7f25047..82a515c21b 100644 --- a/compat/win32/dirent.c +++ b/compat/win32/dirent.c @@ -4,92 +4,88 @@ struct DIR { struct dirent dd_dir; /* includes d_type */ HANDLE dd_handle; /* FindFirstFile handle */ int dd_stat; /* 0-based index */ - char dd_name[1]; /* extend struct */ }; +static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) +{ + /* copy file name from WIN32_FIND_DATA to dirent */ + memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name)); + + /* Set file type, based on WIN32_FIND_DATA */ + if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ent->d_type = DT_DIR; + else + ent->d_type = DT_REG; +} + DIR *opendir(const char *name) { - DWORD attrs = GetFileAttributesA(name); + char pattern[MAX_PATH]; + WIN32_FIND_DATAA fdata; + HANDLE h; int len; - DIR *p; + DIR *dir; - /* check for valid path */ - if (attrs == INVALID_FILE_ATTRIBUTES) { - errno = ENOENT; + /* check that name is not NULL */ + if (!name) { + errno = EINVAL; return NULL; } - - /* check if it's a directory */ - if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) { - errno = ENOTDIR; - return NULL; - } - /* check that the pattern won't be too long for FindFirstFileA */ len = strlen(name); - if (is_dir_sep(name[len - 1])) - len--; if (len + 2 >= MAX_PATH) { errno = ENAMETOOLONG; return NULL; } + /* copy name to temp buffer */ + memcpy(pattern, name, len + 1); - p = malloc(sizeof(DIR) + len + 2); - if (!p) + /* append optional '/' and wildcard '*' */ + if (len && !is_dir_sep(pattern[len - 1])) + pattern[len++] = '/'; + pattern[len++] = '*'; + pattern[len] = 0; + + /* open find handle */ + h = FindFirstFileA(pattern, &fdata); + if (h == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError(); + errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); return NULL; + } - memset(p, 0, sizeof(DIR) + len + 2); - strcpy(p->dd_name, name); - p->dd_name[len] = '/'; - p->dd_name[len+1] = '*'; - - p->dd_handle = INVALID_HANDLE_VALUE; - return p; + /* initialize DIR structure and copy first dir entry */ + dir = xmalloc(sizeof(DIR)); + dir->dd_handle = h; + dir->dd_stat = 0; + finddata2dirent(&dir->dd_dir, &fdata); + return dir; } struct dirent *readdir(DIR *dir) { - WIN32_FIND_DATAA buf; - HANDLE handle; - - if (!dir || !dir->dd_handle) { + if (!dir) { errno = EBADF; /* No set_errno for mingw */ return NULL; } - if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) { - DWORD lasterr; - handle = FindFirstFileA(dir->dd_name, &buf); - lasterr = GetLastError(); - dir->dd_handle = handle; - if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { - errno = err_win_to_posix(lasterr); + /* if first entry, dirent has already been set up by opendir */ + if (dir->dd_stat) { + /* get next entry and convert from WIN32_FIND_DATA to dirent */ + WIN32_FIND_DATAA fdata; + if (FindNextFileA(dir->dd_handle, &fdata)) { + finddata2dirent(&dir->dd_dir, &fdata); + } else { + DWORD lasterr = GetLastError(); + /* POSIX says you shouldn't set errno when readdir can't + find any more files; so, if another error we leave it set. */ + if (lasterr != ERROR_NO_MORE_FILES) + errno = err_win_to_posix(lasterr); return NULL; } - } else if (dir->dd_handle == INVALID_HANDLE_VALUE) { - return NULL; - } else if (!FindNextFileA(dir->dd_handle, &buf)) { - DWORD lasterr = GetLastError(); - FindClose(dir->dd_handle); - dir->dd_handle = INVALID_HANDLE_VALUE; - /* POSIX says you shouldn't set errno when readdir can't - find any more files; so, if another error we leave it set. */ - if (lasterr != ERROR_NO_MORE_FILES) - errno = err_win_to_posix(lasterr); - return NULL; } - /* We get here if `buf' contains valid data. */ - strcpy(dir->dd_dir.d_name, buf.cFileName); ++dir->dd_stat; - - /* Set file type, based on WIN32_FIND_DATA */ - dir->dd_dir.d_type = 0; - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - dir->dd_dir.d_type |= DT_DIR; - else - dir->dd_dir.d_type |= DT_REG; - return &dir->dd_dir; } @@ -100,8 +96,7 @@ int closedir(DIR *dir) return -1; } - if (dir->dd_handle != INVALID_HANDLE_VALUE) - FindClose(dir->dd_handle); + FindClose(dir->dd_handle); free(dir); return 0; } From c489b7f280fc26a38530d1e755bd9ac8703b2586 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 18:04:16 +0100 Subject: [PATCH 2127/3720] Win32: fix potential multi-threading issue ...by removing a static buffer in do_stat_internal. Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index b8928575d7..8052ce0197 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) static int do_stat_internal(int follow, const char *file_name, struct stat *buf) { int namelen; - static char alt_name[PATH_MAX]; + char alt_name[PATH_MAX]; if (!do_lstat(follow, file_name, buf)) return 0; From b63c63286a5cc9d40600a5163049c15fa1bf6e68 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 19:47:23 +0100 Subject: [PATCH 2128/3720] Win32: move main macro to a function The code in the MinGW main macro is getting more and more complex, move to a separate initialization function for readabiliy and extensibility. Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 15 +++++++++++++++ compat/mingw.h | 14 ++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8052ce0197..68dfdf1365 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1868,3 +1868,18 @@ int mingw_offset_1st_component(const char *path) return offset + is_dir_sep(path[offset]); } + +void mingw_startup() +{ + /* copy executable name to argv[0] */ + __argv[0] = xstrdup(_pgmptr); + + /* initialize critical section for waitpid pinfo_t list */ + InitializeCriticalSection(&pinfo_cs); + + /* set up default file mode and file modes for stdin/out/err */ + _fmode = _O_BINARY; + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); + _setmode(_fileno(stderr), _O_BINARY); +} diff --git a/compat/mingw.h b/compat/mingw.h index ef5226c7c4..a832520c6c 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -327,22 +327,16 @@ char **make_augmented_environ(const char *const *vars); void free_environ(char **env); /* - * A replacement of main() that ensures that argv[0] has a path - * and that default fmode and std(in|out|err) are in binary mode + * A replacement of main() that adds win32 specific initialization. */ +void mingw_startup(); #define main(c,v) dummy_decl_mingw_main(); \ static int mingw_main(); \ int main(int argc, const char **argv) \ { \ - extern CRITICAL_SECTION pinfo_cs; \ - _fmode = _O_BINARY; \ - _setmode(_fileno(stdin), _O_BINARY); \ - _setmode(_fileno(stdout), _O_BINARY); \ - _setmode(_fileno(stderr), _O_BINARY); \ - argv[0] = xstrdup(_pgmptr); \ - InitializeCriticalSection(&pinfo_cs); \ - return mingw_main(argc, argv); \ + mingw_startup(); \ + return mingw_main(__argc, __argv); \ } \ static int mingw_main(c,v) From a05e9a868935f1ae8664d3d5881d97c8a094bf87 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 7 Jan 2011 19:52:20 +0100 Subject: [PATCH 2129/3720] MinGW: disable CRT command line globbing MingwRT listens to _CRT_glob to decide if __getmainargs should perform globbing, with the default being that it should. Unfortunately, __getmainargs globbing is sub-par; for instance patterns like "*.c" will only match c-sources in the current directory. Disable __getmainargs' command line wildcard expansion, so these patterns will be left untouched, and handled by Git's superior built-in globbing instead. MSVC defaults to no globbing, so we don't need to do anything in that case. This fixes t5505 and t7810. Signed-off-by: Karsten Blees Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 68dfdf1365..0b0d405c68 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1869,6 +1869,12 @@ int mingw_offset_1st_component(const char *path) return offset + is_dir_sep(path[offset]); } +/* + * Disable MSVCRT command line wildcard expansion (__getmainargs called from + * mingw startup code, see init.c in mingw runtime). + */ +int _CRT_glob = 0; + void mingw_startup() { /* copy executable name to argv[0] */ From f04ee9c28e307cef1191774b3135c47736d9feb3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 6 Aug 2011 15:04:48 +0200 Subject: [PATCH 2130/3720] Support NO_UNIX_SOCKETS The year is 2011AD. Desktop computers are entirely occupied by POSIX-conforming operating systems. Well, not entirely...! One small operating system of indomitable APIs still holds out against the invaders, their POSIX functions and datatypes... and their Unix sockets. Signed-off-by: Johannes Schindelin --- Makefile | 6 ++++++ unix-socket.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Makefile b/Makefile index 6d67e444de..234d0af0fd 100644 --- a/Makefile +++ b/Makefile @@ -258,6 +258,8 @@ all:: # dependency rules. # # Define NATIVE_CRLF if your platform uses CRLF for line endings. +# +# Define NO_UNIX_SOCKETS if your platform does not have them. GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -1214,6 +1216,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_INET_NTOP = YesPlease NO_POSIX_GOODIES = UnfortunatelyYes NO_D_INO_IN_DIRENT = YesPlease + NO_UNIX_SOCKETS = UnfortunatelyNot COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/winansi.o \ @@ -1624,6 +1627,9 @@ endif ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT export GIT_TEST_CMP_USE_COPIED_CONTEXT endif +ifdef NO_UNIX_SOCKETS + COMPAT_CFLAGS += -DNO_UNIX_SOCKETS=1 +endif ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks diff --git a/unix-socket.c b/unix-socket.c index cf9890f57c..8defa80c31 100644 --- a/unix-socket.c +++ b/unix-socket.c @@ -1,6 +1,19 @@ #include "cache.h" #include "unix-socket.h" +#ifdef NO_UNIX_SOCKETS +int unix_stream_connect(const char *path) +{ + errno = ENOSYS; + return -1; +} + +int unix_stream_listen(const char *path) +{ + errno = ENOSYS; + return -1; +} +#else static int unix_stream_socket(void) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); @@ -56,3 +69,4 @@ int unix_stream_listen(const char *path) return fd; } +#endif From a3d6f8220ade41968059a3bcf3ab1796633cc89c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 6 Aug 2011 15:05:52 +0200 Subject: [PATCH 2131/3720] Add missing #include According to POSIX.1-2001, dirname() is declared in libgen.h. Signed-off-by: Johannes Schindelin --- credential-cache--daemon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/credential-cache--daemon.c b/credential-cache--daemon.c index f520347f60..ada4ed1d1c 100644 --- a/credential-cache--daemon.c +++ b/credential-cache--daemon.c @@ -1,6 +1,7 @@ #include "cache.h" #include "credential.h" #include "unix-socket.h" +#include struct credential_cache_entry { struct credential item; From d1478d8a1e8c09e5ce4b77b76bee99729bd2e777 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 25 Sep 2011 03:02:57 -0500 Subject: [PATCH 2132/3720] Gitweb: add support for Alex Gorbatchev's SyntaxHighlighter in Javascript Gitweb is not exactly what you would call server-friendly, so let's offload one more task onto the client. To enable this, put something like this into your gitweb_config.perl: $feature{'syntaxhighlighter_js'}{'default'} = [{ url => '/SyntaxHighlighter/', style => 'Django', theme => 'FadeToGrey' }]; and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the directory you specified via the 'url' parameter. Signed-off-by: Johannes Schindelin --- gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 86b17255dc..67e7284a39 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -6450,7 +6450,19 @@ sub git_blob { # we can have blame only for text/* mimetype $have_blame &&= ($mimetype =~ m!^text/!); + my $highlight_js = gitweb_check_feature('syntaxhighlighter_js'); + if ($highlight_js) { + push @stylesheets, $highlight_js->{url} . '/styles/shCore' + . $highlight_js->{style} . '.css'; + push @stylesheets, $highlight_js->{url} . '/styles/shTheme' + . $highlight_js->{theme} . '.css'; + } + my $highlight = gitweb_check_feature('highlight'); + if ($highlight_js && $highlight) { + die_error(500, 'The highlight and syntaxhighlighter_js are' + . 'mutually exclusive'); + } my $syntax = guess_file_syntax($highlight, $mimetype, $file_name); $fd = run_highlighter($fd, $highlight, $syntax) if $syntax; @@ -6498,6 +6510,58 @@ sub git_blob { href(action=>"blob_plain", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name) . qq!" />\n!; + } elsif ($highlight_js) { + my $ext = $file_name; + $ext =~ s/.*\.//; + print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 46146db5fc1dae6c558933f95d0a9c4393cfc499 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2133/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 67e7284a39..b6f3ee8820 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4256,7 +4256,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 936e96db099c4e498e499ef5c17ceee8135a8eb3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2134/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index b6f3ee8820..7df5150d9b 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6563,7 +6563,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From d2b80c48143d44b24349c3b4c630e7ed69d63bfa Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2135/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0b0d405c68..57d41ddc17 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 2cbf779467f05f9c54586447b967566953545015 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2136/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index a832520c6c..3aa80bb33a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 76cc4e01a0ec4778bb47b63c9f900352f8fe6d35 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2137/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index ce9dd980eb..b659c9f4ef 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From dab43967247b14d4fcc0a94c1b629df9eb3501a5 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2138/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 03296b7eb8..b6682881de 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index d07554c884..5fbed38637 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 601f6f655c..19a3c09519 100644
--- a/cache.h
+++ b/cache.h
@@ -601,6 +601,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index 6ef0cc4f99..793aadf9ea 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index b659c9f4ef..78ff4c5832 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -321,6 +318,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index a9e23594bd..f24becb998 100644
--- a/config.c
+++ b/config.c
@@ -662,6 +662,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 8174b703c4..c783e86098 100644
--- a/environment.c
+++ b/environment.c
@@ -59,6 +59,7 @@ char *notes_ref_name;
 int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
 struct startup_info *startup_info;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 5ef8ff76f6..1adbb55f33 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -575,4 +575,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 39dbe990edcfafd40605afee49b44fd5db999103 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2139/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 793aadf9ea..d4b1cafd8b 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 8280446337037fbfa10c7785899d1ebd139e53fb Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2140/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 8327b977237a78ceea70b0472d6b3b3809b3b606 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2141/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index fd6a43d0a2..3c6dab147e 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1269,9 +1269,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2079,7 +2076,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2091,12 +2088,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2117,18 +2121,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2149,20 +2150,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 73f8a642c92fefb74d20457d44008d6a832cb790 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2142/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 3c6dab147e..c5037685e3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 647921ae424ed6c7cc13730df4474bfc46ff4d4f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2143/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 4cde0c493b..6b18e34726 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9480,7 +9480,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 2a8e01a189b693cb82159c016995e22aa87ccba9 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2144/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From c02d613e7888604106adc919bbb0d603898bc99e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2145/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From f9ef98f9d37480f86a99d9d0ce45da3b54a50044 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2146/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index b6682881de..5426d775a5 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1638,6 +1638,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 261b610d24..47d465f9b2 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -87,7 +89,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -391,6 +398,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -422,6 +467,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -450,6 +502,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 6d95a38a3626f914a4fbdeaa27f0767493a4fd75 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2147/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 91607c5878..63202a8d11 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1050,7 +1050,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 9fa0780c542caed0742cc04364f1951214468749 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2148/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 63202a8d11..bee26dbbf7 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1142,7 +1142,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From eb8fa8ca2c82c904d199285c56c37a1d649693cd Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2149/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 0b4ecac855..b2703fcb02 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -158,7 +158,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -357,7 +357,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index d4b1cafd8b..b0dd5b6e23 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1821,3 +1821,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 78ff4c5832..3078f39678 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -352,3 +352,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index f24becb998..fe38074678 100644
--- a/config.c
+++ b/config.c
@@ -869,7 +869,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK)) {
diff --git a/git-compat-util.h b/git-compat-util.h
index 1adbb55f33..aec3f843eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -579,4 +579,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From e40ee31109c588a30fe240146febc4d8896e3f6a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2150/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From 587a406c4b575fbf25d9a46e969990fe903420eb Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2151/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 9042432e23..3ed18a1886 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -557,7 +557,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -726,7 +727,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -802,7 +804,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -826,7 +828,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From af3889de8d6b0e021313509f37c8b4b059f2371b Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2152/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index bdd9513b84..eadb24c867 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From e40fa94421cbaad5748dd764ba3be132c4c4ecbb Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2153/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 19a3c09519..b1d12cf9a8 100644
--- a/cache.h
+++ b/cache.h
@@ -754,7 +754,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index b0dd5b6e23..3bc06888c3 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1839,3 +1839,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 3078f39678..ee3104b6a9 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -312,6 +312,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index aec3f843eb..8c9d4ed1e5 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 9cc96c96465d9e161f22d879e0a9ae71349e5db0 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2154/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index b2703fcb02..b0c53c346d 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -357,7 +357,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From a12bace0064dde6a9157731a42319dfde9298e2f Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2155/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 3bc06888c3..3825e3aa68 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1842,23 +1842,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 275b90bc5bb28a2107fb7c8bf7185b895b9ee1c8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2156/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index c5037685e3..0d5bd3465f 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1177,6 +1177,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From d30e0a1e17e9939b58f6b260c1e9d7f12c6949d1 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2157/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6b18e34726..2a92e20f06 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -369,7 +369,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9480,18 +9480,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9502,6 +9491,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 97a83c468ca5dc4647e62403a0e7da3f4aad56f2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2158/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 3825e3aa68..83f06f6e74 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 465a4701bf1965a8cd4fe5ddb5c8d765be078749 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2159/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index ee3104b6a9..01ce671ab2 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -293,9 +293,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 09a771abaca0acbe2e6d51185e51aefb57c953e9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2160/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 841953a73ea8c19aa2740508a3eb6997aee450a2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2161/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From bc9860d3d3bce4e0099dec1835725cd6b63bb718 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2162/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index e7694a3a4c..29222b3fbf 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -549,7 +549,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 1f992affa755316d8b6725f89210785a2dd790c7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2163/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 85d64b244d..473e559036 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4267,6 +4267,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 4e7721908804d242febbdfdd63873883ccb14843 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2164/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 473e559036..6e02f179c0 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4282,7 +4282,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 2af54c728d9caca8b11f3006f4c1d02eb78dab89 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2165/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index fb3465f50c..75a3c49cec 100644
--- a/http.c
+++ b/http.c
@@ -3,6 +3,7 @@
 #include "sideband.h"
 #include "run-command.h"
 #include "url.h"
+#include "exec_cmd.h"
 
 int data_received;
 int active_requests;
@@ -139,6 +140,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -146,17 +159,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 9369839d7d88d8840fd822bec5510a79213a6b0f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2166/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index c59b0c98fe..68fd050e94 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From 308f835490b7a69a463cb5a558a779028566b35f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2167/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 47d465f9b2..0e4f6ea365 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -401,7 +401,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 97adaf03108a23d90b406e4a853045f22da2c855 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2168/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 024b87868a..08d641c820 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "dir.h"
 #include "thread-utils.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -187,6 +188,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_checkattr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -197,6 +214,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -514,6 +534,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -979,6 +1002,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 9307aff895fc41765a1ffe588f0f31f46b661be6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2169/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index e02bb2b291..4be5126f84 100644
--- a/Makefile
+++ b/Makefile
@@ -274,7 +274,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From 9481660182b8d37ee1bb103d72529ac31e216483 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2170/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 83f06f6e74..d4d3fdfb2e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1826,7 +1826,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 57825713ae17db9b3e7bf57b53b77288a71deb9e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2171/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 4be5126f84..5abc490e95 100644
--- a/Makefile
+++ b/Makefile
@@ -1940,7 +1940,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -1980,6 +1980,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 6593b01519d56ffa35bf497103fc2f399c000ff0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2172/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 63849836c8..2ef2ec912e 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 81c5a0857443b338b5be37bf8167529c433b3e7d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2173/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 08d641c820..2a3cf14ecf 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1067,6 +1067,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From a3fc7b61642fb90da1ff28af591031c5de0e7d58 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2174/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 2a3cf14ecf..8cf130ae87 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1067,7 +1067,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From 54ca94a9fbd28e8e94eca8814adb9d1c6604b5b0 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2175/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index c279bfb244..0b9f8dd5b5 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -928,22 +928,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -958,11 +962,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 5202332a58cda0b853c9942a6d2f0a5e70d1e37a Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2176/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index d4d3fdfb2e..b8928575d7 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 2ad423493d8226ba0b43891612ef384d96b75c7a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2177/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 457d68e68a188a368f82df84bd7e1fb275e296b5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2178/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From 1b06ac473c15a18a87a5fa1dd22ecfad011e92d2 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2179/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2180/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 928a62f626..70e6284e40 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2181/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From dcd8edea1d697554aba8b10c00495817a180ec50 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2182/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2183/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 01ce671ab2..ef5226c7c4 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From c61187148eaac88ca1545379f00500f3fbbf5b14 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2184/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 5abc490e95..3dccdf6f77 100644
--- a/Makefile
+++ b/Makefile
@@ -1122,6 +1122,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1213,6 +1214,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 40f1ff58020a32909ac505c4dacc3fb661b0442e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2185/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From cb1769fc5344e8543d15b8eefbb118ffbdb65f62 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2186/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From b199e899ef59430b0d9aaee68f16d371b5cccab1 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2187/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From c1641da74d782fc027b6dc9505ece548a92de3b6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2188/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 82d8bd39d9afae6fce46b370568a4f44162a4d5a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2189/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index b8928575d7..8052ce0197 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 064ff1edf7e242366055e0f90ddd417c5a6a5e97 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2190/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8052ce0197..68dfdf1365 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1868,3 +1868,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index ef5226c7c4..a832520c6c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -327,22 +327,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 45cfa3506b1f224969c3f08deb560a89d70ba1ce Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2191/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 68dfdf1365..0b0d405c68 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1869,6 +1869,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 458d6ffd0a619243d08fd4dc749140cc8932f8ef Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2192/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 6e02f179c0..59ac52c99a 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6461,7 +6461,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6509,6 +6521,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 610631e49cf757b1f8966564e55f5d344a11721e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2193/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 59ac52c99a..33382638e1 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4267,7 +4267,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 347b83c2c08214a1c5342502bcf8ff28b1b76322 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2194/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 33382638e1..723e1ba35e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6574,7 +6574,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 01d01813428e2c75ca2c921a1a78c16d8389d5ae Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2195/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0b0d405c68..57d41ddc17 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From ad20b11d0de03a16b165236e83f8880c32c5495e Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2196/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index a832520c6c..3aa80bb33a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 1ad7341d9738e4ca8e84a13b4ce4a3153b4e92b2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Oct 2011 15:17:31 -0500
Subject: [PATCH 2197/3720] fixup! grep -I: do not bother to read known-binary
 files

---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 8cf130ae87..95ba4a08e2 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -198,7 +198,7 @@ static int skip_binary(struct grep_opt *opt, const char *filename)
 			attr_text = git_attr("text");
 		memset(&check, 0, sizeof(check));
 		check.attr = attr_text;
-		return !git_checkattr(filename, 1, &check) &&
+		return !git_check_attr(filename, 1, &check) &&
 				ATTR_FALSE(check.value);
 	}
 	return 0;

From 0a032919e01f1485de4a2df52c5f3c54ac92d312 Mon Sep 17 00:00:00 2001
From: Jeff King 
Date: Mon, 10 Oct 2011 17:22:47 +0200
Subject: [PATCH 2198/3720] fix phantom untracked files when core.ignorecase is
 set

When core.ignorecase is turned on and there are stale index
entries, "git commit" can sometimes report directories as
untracked, even though they contain tracked files.

You can see an example of this with:

    # make a case-insensitive repo
    git init repo && cd repo &&
    git config core.ignorecase true &&

    # with some tracked files in a subdir
    mkdir subdir &&
    > subdir/one &&
    > subdir/two &&
    git add . &&
    git commit -m base &&

    # now make the index entries stale
    touch subdir/* &&

    # and then ask commit to update those entries and show
    # us the status template
    git commit -a

which will report "subdir/"  as untracked, even though it
clearly contains two tracked files. What is happening in the
commit program is this:

  1. We load the index, and for each entry, insert it into the index's
     name_hash. In addition, if ignorecase is turned on, we make an
     entry in the name_hash for the directory (e.g., "contrib/"), which
     uses the following code from 5102c61's hash_index_entry_directories:

        hash = hash_name(ce->name, ptr - ce->name);
        if (!lookup_hash(hash, &istate->name_hash)) {
                pos = insert_hash(hash, &istate->name_hash);
		if (pos) {
			ce->next = *pos;
			*pos = ce;
		}
        }

     Note that we only add the directory entry if there is not already an
     entry.

  2. We run add_files_to_cache, which gets updated information for each
     cache entry. It helpfully inserts this information into the cache,
     which calls replace_index_entry. This in turn calls
     remove_name_hash() on the old entry, and add_name_hash() on the new
     one. But remove_name_hash doesn't actually remove from the hash, it
     only marks it as "no longer interesting" (from cache.h):

      /*
       * We don't actually *remove* it, we can just mark it invalid so that
       * we won't find it in lookups.
       *
       * Not only would we have to search the lists (simple enough), but
       * we'd also have to rehash other hash buckets in case this makes the
       * hash bucket empty (common). So it's much better to just mark
       * it.
       */
      static inline void remove_name_hash(struct cache_entry *ce)
      {
              ce->ce_flags |= CE_UNHASHED;
      }

     This is OK in the specific-file case, since the entries in the hash
     form a linked list, and we can just skip the "not here anymore"
     entries during lookup.

     But for the directory hash entry, we will _not_ write a new entry,
     because there is already one there: the old one that is actually no
     longer interesting!

  3. While traversing the directories, we end up in the
     directory_exists_in_index_icase function to see if a directory is
     interesting. This in turn checks index_name_exists, which will
     look up the directory in the index's name_hash. We see the old,
     deleted record, and assume there is nothing interesting. The
     directory gets marked as untracked, even though there are index
     entries in it.

The problem is in the code I showed above:

        hash = hash_name(ce->name, ptr - ce->name);
        if (!lookup_hash(hash, &istate->name_hash)) {
                pos = insert_hash(hash, &istate->name_hash);
		if (pos) {
			ce->next = *pos;
			*pos = ce;
		}
        }

Having a single cache entry that represents the directory is
not enough; that entry may go away if the index is changed.
It may be tempting to say that the problem is in our removal
method; if we removed the entry entirely instead of simply
marking it as "not here anymore", then we would know we need
to insert a new entry. But that only covers this particular
case of remove-replace. In the more general case, consider
something like this:

  1. We add "foo/bar" and "foo/baz" to the index. Each gets
     their own entry in name_hash, plus we make a "foo/"
     entry that points to "foo/bar".

  2. We remove the "foo/bar" entry from the index, and from
     the name_hash.

  3. We ask if "foo/" exists, and see no entry, even though
     "foo/baz" exists.

So we need that directory entry to have the list of _all_
cache entries that indicate that the directory is tracked.
So that implies making a linked list as we do for other
entries, like:

  hash = hash_name(ce->name, ptr - ce->name);
  pos = insert_hash(hash, &istate->name_hash);
  if (pos) {
	  ce->next = *pos;
	  *pos = ce;
  }

But that's not right either. In fact, it shows a second bug
in the current code, which is that the "ce->next" pointer is
supposed to be linking entries for a specific filename
entry, but here we are overwriting it for the directory
entry. So the same cache entry ends up in two linked lists,
but they share the same "next" pointer.

As it turns out, this second bug can't be triggered in the
current code. The "if (pos)" conditional is totally dead
code; pos will only be non-NULL if there was an existing
hash entry, and we already checked that there wasn't one
through our call to lookup_hash.

But fixing the first bug means taking out that call to
lookup_hash, which is going to activate the buggy dead code,
and we'll end up splicing the two linked lists together.

So we need to have a separate next pointer for the list in
the directory bucket, and we need to traverse that list in
index_name_exists when we are looking up a directory.

This bloats "struct cache_entry" by a few bytes. Which is
annoying, because it's only necessary when core.ignorecase
is enabled. There's not an easy way around it, short of
separating out the "next" pointers from cache_entry entirely
(i.e., having a separate "cache_entry_list" struct that gets
stored in the name_hash). In practice, it probably doesn't
matter; we have thousands of cache entries, compared to the
millions of objects (where adding 4 bytes to the struct
actually does impact performance).

Signed-off-by: Jeff King 
---
 cache.h     |  1 +
 name-hash.c | 15 ++++++++-------
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/cache.h b/cache.h
index 0242563906..d7883e6fe7 100644
--- a/cache.h
+++ b/cache.h
@@ -168,6 +168,7 @@ struct cache_entry {
 	unsigned int ce_flags;
 	unsigned char sha1[20];
 	struct cache_entry *next;
+	struct cache_entry *dir_next;
 	char name[FLEX_ARRAY]; /* more */
 };
 
diff --git a/name-hash.c b/name-hash.c
index c6b6a3fe4c..225dd76995 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -57,12 +57,10 @@ static void hash_index_entry_directories(struct index_state *istate, struct cach
 		if (*ptr == '/') {
 			++ptr;
 			hash = hash_name(ce->name, ptr - ce->name);
-			if (!lookup_hash(hash, &istate->name_hash)) {
-				pos = insert_hash(hash, ce, &istate->name_hash);
-				if (pos) {
-					ce->next = *pos;
-					*pos = ce;
-				}
+			pos = insert_hash(hash, ce, &istate->name_hash);
+			if (pos) {
+				ce->dir_next = *pos;
+				*pos = ce;
 			}
 		}
 	}
@@ -166,7 +164,10 @@ struct cache_entry *index_name_exists(struct index_state *istate, const char *na
 			if (same_name(ce, name, namelen, icase))
 				return ce;
 		}
-		ce = ce->next;
+		if (icase && name[namelen - 1] == '/')
+			ce = ce->dir_next;
+		else
+			ce = ce->next;
 	}
 
 	/*

From ef4bffc21d4fb172217bb32eaee55e912580c5d4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 10 Oct 2011 15:58:41 -0500
Subject: [PATCH 2199/3720] t1020: disable the pwd test on MinGW

It fails both for line ending and for DOS path reasons.

Signed-off-by: Johannes Schindelin 
---
 t/t1020-subdirectory.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index 3b1b985996..e23ac0e69d 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -118,7 +118,7 @@ test_expect_success 'alias expansion' '
 	)
 '
 
-test_expect_success '!alias expansion' '
+test_expect_success NOT_MINGW '!alias expansion' '
 	pwd >expect &&
 	(
 		git config alias.test !pwd &&

From 2e51681cb9dec70d263702d48091293868fbb172 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 10 Oct 2011 16:12:00 -0500
Subject: [PATCH 2200/3720] t1402: Ignore a few cases that must fail due to DOS
 path expansion

Signed-off-by: Johannes Schindelin 
---
 t/t1402-check-ref-format.sh | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 710fccad36..1a5e34320a 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -36,7 +36,7 @@ invalid_ref 'refs///heads/foo'
 valid_ref 'refs///heads/foo' --normalize
 invalid_ref 'heads/foo/'
 invalid_ref '/heads/foo'
-valid_ref '/heads/foo' --normalize
+test_have_prereq MINGW || valid_ref '/heads/foo' --normalize
 invalid_ref '///heads/foo'
 valid_ref '///heads/foo' --normalize
 invalid_ref './foo'
@@ -120,9 +120,12 @@ invalid_ref "$ref" --allow-onelevel
 invalid_ref "$ref" --refspec-pattern
 invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
 invalid_ref "$ref" --normalize
-valid_ref "$ref" '--allow-onelevel --normalize'
-invalid_ref "$ref" '--refspec-pattern --normalize'
-valid_ref "$ref" '--refspec-pattern --allow-onelevel --normalize'
+if test_have_prereq NOT_MINGW
+then
+	valid_ref "$ref" '--allow-onelevel --normalize'
+	invalid_ref "$ref" '--refspec-pattern --normalize'
+	valid_ref "$ref" '--refspec-pattern --allow-onelevel --normalize'
+fi
 
 test_expect_success "check-ref-format --branch @{-1}" '
 	T=$(git write-tree) &&
@@ -166,10 +169,10 @@ invalid_ref_normalized() {
 
 valid_ref_normalized 'heads/foo' 'heads/foo'
 valid_ref_normalized 'refs///heads/foo' 'refs/heads/foo'
-valid_ref_normalized '/heads/foo' 'heads/foo'
+test_have_prereq MINGW || valid_ref_normalized '/heads/foo' 'heads/foo'
 valid_ref_normalized '///heads/foo' 'heads/foo'
 invalid_ref_normalized 'foo'
-invalid_ref_normalized '/foo'
+test_have_prereq MINGW || invalid_ref_normalized '/foo'
 invalid_ref_normalized 'heads/foo/../bar'
 invalid_ref_normalized 'heads/./foo'
 invalid_ref_normalized 'heads\foo'

From f0e86b3b664bbfdc7e8fabdb01518347f7e0d2f8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Oct 2011 14:07:48 -0500
Subject: [PATCH 2201/3720] Fix is_gitfile() for files larger than PATH_MAX
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The logic to check whether a file is a gitfile used the heuristics that
the file cannot be larger than PATH_MAX. But in that case it returned the
wrong value. Our test cases do not cover this, as the bundle files
produced are smaller than PATH_MAX. Except on Windows.

While at it, fix the faulty logic that the path stored in a gitfile cannot
be larger than PATH_MAX-sizeof("gitfile: ").

Problem identified by running the test suite in msysGit, offending commit
identified by Jörg Rosenkranz.

Signed-off-by: Johannes Schindelin 
---
 transport.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/transport.c b/transport.c
index f3195c0ae4..57138d908a 100644
--- a/transport.c
+++ b/transport.c
@@ -868,8 +868,8 @@ static int is_gitfile(const char *url)
 		return 0;
 	if (!S_ISREG(st.st_mode))
 		return 0;
-	if (st.st_size < 10 || st.st_size > PATH_MAX)
-		return 1;
+	if (st.st_size < 10 || st.st_size > 9 + PATH_MAX)
+		return 0;
 
 	fd = open(url, O_RDONLY);
 	if (fd < 0)

From 6ecb26836b8fe1f3eefe306b79f3652b125d9be9 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 5 Oct 2011 11:14:38 +0200
Subject: [PATCH 2202/3720] git-svn: On MSYS, escape and quote SVN_SSH also if
 set by the user

While GIT_SSH does not require any escaping / quoting (e.g. for paths
containing spaces), SVN_SSH requires it due to its use in a Perl script.

Previously, SVN_SSH has only been escaped and quoted automatically if it
was unset and thus derived from GIT_SSH. For user convenience, do the
escaping and quoting also for a SVN_SSH set by the user. This way, the
user is able to use the same unescaped and unquoted syntax for GIT_SSH
and SVN_SSH.

Signed-off-by: Sebastian Schuberth 
---
 git-svn.perl | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index a0410f0554..3b33379473 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -22,14 +22,13 @@ $Git::SVN::default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn';
 $Git::SVN::Ra::_log_window_size = 100;
 $Git::SVN::_minimize_url = 'unset';
 
-if (! exists $ENV{SVN_SSH}) {
-	if (exists $ENV{GIT_SSH}) {
-		$ENV{SVN_SSH} = $ENV{GIT_SSH};
-		if ($^O eq 'msys') {
-			$ENV{SVN_SSH} =~ s/\\/\\\\/g;
-			$ENV{SVN_SSH} =~ s/(.*)/"$1"/;
-		}
-	}
+if (! exists $ENV{SVN_SSH} && exists $ENV{GIT_SSH}) {
+	$ENV{SVN_SSH} = $ENV{GIT_SSH};
+}
+
+if (exists $ENV{SVN_SSH} && $^O eq 'msys') {
+	$ENV{SVN_SSH} =~ s/\\/\\\\/g;
+	$ENV{SVN_SSH} =~ s/(.*)/"$1"/;
 }
 
 $Git::SVN::Log::TZ = $ENV{TZ};

From 5f4d3f50f6365ee0a0a64726995459981754fb56 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Wed, 12 Oct 2011 13:10:56 +0100
Subject: [PATCH 2203/3720] t9901: fix line-ending dependency on windows

Signed-off-by: Pat Thoyts 
---
 t/t9901-git-web--browse.sh | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/t/t9901-git-web--browse.sh b/t/t9901-git-web--browse.sh
index 7906e5d032..1185b42246 100755
--- a/t/t9901-git-web--browse.sh
+++ b/t/t9901-git-web--browse.sh
@@ -12,7 +12,7 @@ test_expect_success \
 	echo http://example.com/foo\&bar >expect &&
 	git config browser.custom.cmd echo &&
 	git web--browse --browser=custom \
-		http://example.com/foo\&bar >actual &&
+		http://example.com/foo\&bar | tr -d "\r" >actual &&
 	test_cmp expect actual
 '
 
@@ -21,7 +21,7 @@ test_expect_success \
 	echo http://example.com/foo\;bar >expect &&
 	git config browser.custom.cmd echo &&
 	git web--browse --browser=custom \
-		http://example.com/foo\;bar >actual &&
+		http://example.com/foo\;bar | tr -d "\r" >actual &&
 	test_cmp expect actual
 '
 
@@ -30,7 +30,7 @@ test_expect_success \
 	echo http://example.com/foo#bar >expect &&
 	git config browser.custom.cmd echo &&
 	git web--browse --browser=custom \
-		http://example.com/foo#bar >actual &&
+		http://example.com/foo#bar | tr -d "\r" >actual &&
 	test_cmp expect actual
 '
 
@@ -44,7 +44,7 @@ test_expect_success \
 	chmod +x "fake browser" &&
 	git config browser.w3m.path "`pwd`/fake browser" &&
 	git web--browse --browser=w3m \
-		http://example.com/foo >actual &&
+		http://example.com/foo | tr -d "\r" >actual &&
 	test_cmp expect actual
 '
 
@@ -59,7 +59,7 @@ test_expect_success \
 		}
 		f" &&
 	git web--browse --browser=custom \
-		http://example.com/foo >actual &&
+		http://example.com/foo | tr -d "\r" >actual &&
 	test_cmp expect actual
 '
 

From e7b53f54f99eb1a93721ee13cbfc1124342cff5b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 12 Oct 2011 12:05:48 -0500
Subject: [PATCH 2204/3720] t9001: do not fail only due to CR/LF issues

Signed-off-by: Johannes Schindelin 
---
 t/t9001-send-email.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 579ddb7572..7d75738ad4 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -23,6 +23,7 @@ test_expect_success $PREREQ \
       echo do
       echo "  echo \"!\$a!\""
       echo "done >commandline\$output"
+      test_have_prereq MINGW && echo "dos2unix commandline\$output"
       echo "cat > msgtxt\$output"
       ) >fake.sendmail &&
      chmod +x ./fake.sendmail &&

From 2a9f86899614e3331348c91e95c246196146b84a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 12 Oct 2011 15:49:10 -0500
Subject: [PATCH 2205/3720] t9300: do not run --cat-blob-fd related tests on
 MinGW

As diagnosed by Johannes Sixt, msys.dll does not hand through file
descriptors > 2 to child processes, so these test cases cannot passes when
run through an MSys bash.

Signed-off-by: Johannes Schindelin 
---
 t/t9300-fast-import.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index bd32b91d8f..438aaf6b14 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -2237,7 +2237,7 @@ test_expect_success 'R: cat-blob-fd must be a nonnegative integer' '
 	test_must_fail git fast-import --cat-blob-fd=-1 expect <<-EOF &&
 	${blob} blob 11
@@ -2249,7 +2249,7 @@ test_expect_success 'R: print old blob' '
 	test_cmp expect actual
 '
 
-test_expect_success 'R: in-stream cat-blob-fd not respected' '
+test_expect_success NOT_MINGW 'R: in-stream cat-blob-fd not respected' '
 	echo hello >greeting &&
 	blob=$(git hash-object -w greeting) &&
 	cat >expect <<-EOF &&
@@ -2270,7 +2270,7 @@ test_expect_success 'R: in-stream cat-blob-fd not respected' '
 	test_cmp expect actual.1
 '
 
-test_expect_success 'R: print new blob' '
+test_expect_success NOT_MINGW 'R: print new blob' '
 	blob=$(echo "yep yep yep" | git hash-object --stdin) &&
 	cat >expect <<-EOF &&
 	${blob} blob 12
@@ -2288,7 +2288,7 @@ test_expect_success 'R: print new blob' '
 	test_cmp expect actual
 '
 
-test_expect_success 'R: print new blob by sha1' '
+test_expect_success NOT_MINGW 'R: print new blob by sha1' '
 	blob=$(echo "a new blob named by sha1" | git hash-object --stdin) &&
 	cat >expect <<-EOF &&
 	${blob} blob 25

From 2f6af3820eb61f30cf102b345d35028047300b74 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Wed, 12 Oct 2011 10:39:01 -0700
Subject: [PATCH 2206/3720] Restrict ref-like names immediately below $GIT_DIR

We have always dwimmed the user input $string into a ref by first looking
directly inside $GIT_DIR, and then in $GIT_DIR/refs, $GIT_DIR/refs/tags,
etc., and that is what made

    git log HEAD..MERGE_HEAD

work correctly. This however means that

    git rev-parse config
    git log index

would look at $GIT_DIR/config and $GIT_DIR/index and see if they are valid
refs.

To reduce confusion, let's not dwim a path immediately below $GIT_DIR that
is not all-caps.

Helped-by: Jeff King 
Signed-off-by: Junio C Hamano 
---
 refs.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/refs.c b/refs.c
index e3692bd3d8..2eb9c04443 100644
--- a/refs.c
+++ b/refs.c
@@ -994,12 +994,33 @@ const char *ref_fetch_rules[] = {
 	NULL
 };
 
+static int refname_ok_at_root_level(const char *str, int len)
+{
+	if (len >= 5 && !memcmp(str, "refs/", 5))
+		return 1;
+
+	while (len--) {
+		char ch = *str++;
+
+		/*
+		 * Only accept likes of .git/HEAD, .git/MERGE_HEAD at
+		 * the root level as a ref.
+		 */
+		if (ch != '_' && (ch < 'A' || 'Z' < ch))
+			return 0;
+	}
+	return 1;
+}
+
 int refname_match(const char *abbrev_name, const char *full_name, const char **rules)
 {
 	const char **p;
 	const int abbrev_name_len = strlen(abbrev_name);
 
 	for (p = rules; *p; p++) {
+		if (p == rules &&
+		    !refname_ok_at_root_level(abbrev_name, abbrev_name_len))
+			continue;
 		if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {
 			return 1;
 		}
@@ -1100,6 +1121,8 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
 		unsigned char *this_result;
 		int flag;
 
+		if (p == ref_rev_parse_rules && !refname_ok_at_root_level(str, len))
+			continue;
 		this_result = refs_found ? sha1_from_ref : sha1;
 		mksnpath(fullref, sizeof(fullref), *p, len, str);
 		r = resolve_ref(fullref, this_result, 1, &flag);
@@ -1128,6 +1151,8 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
 		char path[PATH_MAX];
 		const char *ref, *it;
 
+		if (p == ref_rev_parse_rules && !refname_ok_at_root_level(str, len))
+			continue;
 		mksnpath(path, sizeof(path), *p, len, str);
 		ref = resolve_ref(path, hash, 1, NULL);
 		if (!ref)
@@ -2045,12 +2070,14 @@ char *shorten_unambiguous_ref(const char *ref, int strict)
 	/* buffer for scanf result, at most ref must fit */
 	short_name = xstrdup(ref);
 
-	/* skip first rule, it will always match */
-	for (i = nr_rules - 1; i > 0 ; --i) {
+	for (i = nr_rules - 1; i >= 0; i--) {
 		int j;
 		int rules_to_fail = i;
 		int short_name_len;
 
+		if (!i && !refname_ok_at_root_level(ref, strlen(ref)))
+			continue;
+
 		if (1 != sscanf(ref, scanf_fmts[i], short_name))
 			continue;
 
@@ -2076,6 +2103,10 @@ char *shorten_unambiguous_ref(const char *ref, int strict)
 			if (i == j)
 				continue;
 
+			if (!j &&
+			    !refname_ok_at_root_level(short_name, short_name_len))
+				continue;
+
 			/*
 			 * the short name is ambiguous, if it resolves
 			 * (with this previous rule) to a valid ref

From 7e4bf67e6a51c7200407017c69b4a67687fe609e Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 13 Oct 2011 12:54:35 +0100
Subject: [PATCH 2207/3720] mergetools: use the correct tool for Beyond Compare
 3 on Windows

On Windows the bcompare tool launches a graphical program and does
not wait for it to terminate. A separate 'bcomp' tool is provided which
will wait for the view to exit so we use this instead.

Reported-by: Werner BEROUX 
Signed-off-by: Pat Thoyts 
---
 mergetools/bc3 | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/mergetools/bc3 b/mergetools/bc3
index 27b3dd48b8..b642bf25dc 100644
--- a/mergetools/bc3
+++ b/mergetools/bc3
@@ -16,5 +16,12 @@ merge_cmd () {
 }
 
 translate_merge_tool_path() {
-	echo bcompare
+	case $(uname -s) in
+	*MINGW*)
+		echo bcomp
+		;;
+	*)
+		echo bcompare
+		;;
+	esac
 }

From e59f1619d0eb9ed2d3c54b8fb83518c71e9f32b4 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Fri, 14 Oct 2011 09:56:16 +0100
Subject: [PATCH 2208/3720] mingw: ensure sockets are initialized before
 calling gethostname

If the Windows sockets subsystem has not been initialized yet then an
attempt to get the hostname returns an error and prints a warning to the
console. This solves this issue for msysGit as seen with 'git fetch'.

Signed-off-by: Pat Thoyts 
---
 compat/mingw.c | 7 +++++++
 compat/mingw.h | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 57d41ddc17..5bb95d9270 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1391,6 +1391,13 @@ static void ensure_socket_initialization(void)
 	initialized = 1;
 }
 
+#undef gethostname
+int mingw_gethostname(char *name, int namelen)
+{
+    ensure_socket_initialization();
+    return gethostname(name, namelen);
+}
+
 #undef gethostbyname
 struct hostent *mingw_gethostbyname(const char *host)
 {
diff --git a/compat/mingw.h b/compat/mingw.h
index 3aa80bb33a..3d99c03b71 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -187,6 +187,9 @@ char *mingw_getcwd(char *pointer, int len);
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 
+int mingw_gethostname(char *host, int namelen);
+#define gethostname mingw_gethostname
+
 struct hostent *mingw_gethostbyname(const char *host);
 #define gethostbyname mingw_gethostbyname
 

From 9079d26c8532bdeb95c6913411f9b5d647a3aac3 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Sun, 16 Oct 2011 21:21:14 -0700
Subject: [PATCH 2209/3720] Fix mismerge at 415cf53

Signed-off-by: Junio C Hamano 
---
 daemon.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/daemon.c b/daemon.c
index 95b7df5d8d..fa283003ea 100644
--- a/daemon.c
+++ b/daemon.c
@@ -20,7 +20,7 @@
 static int log_syslog;
 static int verbose;
 static int reuseaddr;
-static int informative_errors = 1;
+static int informative_errors;
 
 static const char daemon_usage[] =
 "git daemon [--verbose] [--syslog] [--export-all]\n"

From 098977b0d9a7bc98b1c73f9d78009c3558075687 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:10 +0200
Subject: [PATCH 2210/3720] cache.h: add comments for git_path() and
 git_path_submodule()

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 cache.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/cache.h b/cache.h
index e39e160018..99a79d755e 100644
--- a/cache.h
+++ b/cache.h
@@ -660,7 +660,25 @@ extern char *git_pathdup(const char *fmt, ...)
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+
+/*
+ * Return the path of a file within get_git_dir().  The arguments
+ * should be printf-like arguments that produce the filename relative
+ * to get_git_dir().  Return the resulting path, or "/bad-path/" if
+ * there is an error.  The return value is a pointer into a temporary
+ * buffer that will be overwritten without notice.
+ */
 extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+
+/*
+ * Return the path of a file within the git_dir of the submodule
+ * located at path.  The other arguments should be printf-like
+ * arguments that produce the filename relative to "/.git".  If
+ * "/.git" is a gitlink file, follow it to find the actual
+ * submodule git_dir.  Return the resulting path, or "/bad-path/" if
+ * there is an error.  The return value is a pointer into a temporary
+ * buffer that will be overwritten without notice.
+ */
 extern char *git_path_submodule(const char *path, const char *fmt, ...)
 	__attribute__((format (printf, 2, 3)));
 

From 2a5b7a195c233221438ee325de013f805196ee88 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:11 +0200
Subject: [PATCH 2211/3720] struct ref_entry: document name member

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/refs.c b/refs.c
index d8a4fa33e3..68e10eb2ac 100644
--- a/refs.c
+++ b/refs.c
@@ -12,6 +12,7 @@ struct ref_entry {
 	unsigned char flag; /* ISSYMREF? ISPACKED? */
 	unsigned char sha1[20];
 	unsigned char peeled[20];
+	/* The full name of the reference (e.g., "refs/heads/master"): */
 	char name[FLEX_ARRAY];
 };
 

From 685dfe50090748da416f89c9fdead7d678ed5694 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:12 +0200
Subject: [PATCH 2212/3720] refs: rename "refname" variables

Try to consistently use the variable name "refname" when referring to
a string that names a reference.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 276 +++++++++++++++++++++++++++++----------------------------
 refs.h |  26 +++---
 2 files changed, 157 insertions(+), 145 deletions(-)

diff --git a/refs.c b/refs.c
index 68e10eb2ac..a5d560c4e1 100644
--- a/refs.c
+++ b/refs.c
@@ -49,7 +49,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 	return line;
 }
 
-static void add_ref(const char *name, const unsigned char *sha1,
+static void add_ref(const char *refname, const unsigned char *sha1,
 		    int flag, struct ref_array *refs,
 		    struct ref_entry **new_entry)
 {
@@ -57,13 +57,13 @@ static void add_ref(const char *name, const unsigned char *sha1,
 	struct ref_entry *entry;
 
 	/* Allocate it and add it in.. */
-	len = strlen(name) + 1;
+	len = strlen(refname) + 1;
 	entry = xmalloc(sizeof(struct ref_entry) + len);
 	hashcpy(entry->sha1, sha1);
 	hashclr(entry->peeled);
-	if (check_refname_format(name, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
-		die("Reference has invalid format: '%s'", name);
-	memcpy(entry->name, name, len);
+	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
+		die("Reference has invalid format: '%s'", refname);
+	memcpy(entry->name, refname, len);
 	entry->flag = flag;
 	if (new_entry)
 		*new_entry = entry;
@@ -106,20 +106,20 @@ static void sort_ref_array(struct ref_array *array)
 	array->nr = i + 1;
 }
 
-static struct ref_entry *search_ref_array(struct ref_array *array, const char *name)
+static struct ref_entry *search_ref_array(struct ref_array *array, const char *refname)
 {
 	struct ref_entry *e, **r;
 	int len;
 
-	if (name == NULL)
+	if (refname == NULL)
 		return NULL;
 
 	if (!array->nr)
 		return NULL;
 
-	len = strlen(name) + 1;
+	len = strlen(refname) + 1;
 	e = xmalloc(sizeof(struct ref_entry) + len);
-	memcpy(e->name, name, len);
+	memcpy(e->name, refname, len);
 
 	r = bsearch(&e, array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp);
 
@@ -223,7 +223,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 	while (fgets(refline, sizeof(refline), f)) {
 		unsigned char sha1[20];
-		const char *name;
+		const char *refname;
 		static const char header[] = "# pack-refs with:";
 
 		if (!strncmp(refline, header, sizeof(header)-1)) {
@@ -234,9 +234,9 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 			continue;
 		}
 
-		name = parse_ref_line(refline, sha1);
-		if (name) {
-			add_ref(name, sha1, flag, array, &last);
+		refname = parse_ref_line(refline, sha1);
+		if (refname) {
+			add_ref(refname, sha1, flag, array, &last);
 			continue;
 		}
 		if (last &&
@@ -249,9 +249,9 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 	sort_ref_array(array);
 }
 
-void add_extra_ref(const char *name, const unsigned char *sha1, int flag)
+void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
 {
-	add_ref(name, sha1, flag, &extra_refs, NULL);
+	add_ref(refname, sha1, flag, &extra_refs, NULL);
 }
 
 void clear_extra_refs(void)
@@ -397,7 +397,8 @@ static struct ref_array *get_loose_refs(const char *submodule)
 #define MAXDEPTH 5
 #define MAXREFLEN (1024)
 
-static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refname, unsigned char *result)
+static int resolve_gitlink_packed_ref(char *name, int pathlen,
+				      const char *refname, unsigned char *result)
 {
 	int retval = -1;
 	struct ref_entry *ref;
@@ -411,7 +412,9 @@ static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refna
 	return retval;
 }
 
-static int resolve_gitlink_ref_recursive(char *name, int pathlen, const char *refname, unsigned char *result, int recursion)
+static int resolve_gitlink_ref_recursive(char *name, int pathlen,
+					 const char *refname, unsigned char *result,
+					 int recursion)
 {
 	int fd, len = strlen(refname);
 	char buffer[128], *p;
@@ -478,10 +481,10 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re
  * Try to read ref from the packed references.  On success, set sha1
  * and return 0; otherwise, return -1.
  */
-static int get_packed_ref(const char *ref, unsigned char *sha1)
+static int get_packed_ref(const char *refname, unsigned char *sha1)
 {
 	struct ref_array *packed = get_packed_refs(NULL);
-	struct ref_entry *entry = search_ref_array(packed, ref);
+	struct ref_entry *entry = search_ref_array(packed, refname);
 	if (entry) {
 		hashcpy(sha1, entry->sha1);
 		return 0;
@@ -489,18 +492,18 @@ static int get_packed_ref(const char *ref, unsigned char *sha1)
 	return -1;
 }
 
-const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
+const char *resolve_ref(const char *refname, unsigned char *sha1, int reading, int *flag)
 {
 	int depth = MAXDEPTH;
 	ssize_t len;
 	char buffer[256];
-	static char ref_buffer[256];
+	static char refname_buffer[256];
 	char path[PATH_MAX];
 
 	if (flag)
 		*flag = 0;
 
-	if (check_refname_format(ref, REFNAME_ALLOW_ONELEVEL))
+	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
 		return NULL;
 
 	for (;;) {
@@ -511,7 +514,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
 		if (--depth < 0)
 			return NULL;
 
-		git_snpath(path, sizeof(path), "%s", ref);
+		git_snpath(path, sizeof(path), "%s", refname);
 
 		if (lstat(path, &st) < 0) {
 			if (errno != ENOENT)
@@ -520,17 +523,17 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
 			 * The loose reference file does not exist;
 			 * check for a packed reference.
 			 */
-			if (!get_packed_ref(ref, sha1)) {
+			if (!get_packed_ref(refname, sha1)) {
 				if (flag)
 					*flag |= REF_ISPACKED;
-				return ref;
+				return refname;
 			}
 			/* The reference is not a packed reference, either. */
 			if (reading) {
 				return NULL;
 			} else {
 				hashclr(sha1);
-				return ref;
+				return refname;
 			}
 		}
 
@@ -542,8 +545,8 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
 			buffer[len] = 0;
 			if (!prefixcmp(buffer, "refs/") &&
 					!check_refname_format(buffer, 0)) {
-				strcpy(ref_buffer, buffer);
-				ref = ref_buffer;
+				strcpy(refname_buffer, buffer);
+				refname = refname_buffer;
 				if (flag)
 					*flag |= REF_ISSYMREF;
 				continue;
@@ -584,7 +587,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
 				path);
 			return NULL;
 		}
-		ref = strcpy(ref_buffer, buf);
+		refname = strcpy(refname_buffer, buf);
 		if (flag)
 			*flag |= REF_ISSYMREF;
 	}
@@ -593,7 +596,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
 		warning("reference in %s is formatted incorrectly", path);
 		return NULL;
 	}
-	return ref;
+	return refname;
 }
 
 /* The argument to filter_refs */
@@ -603,9 +606,9 @@ struct ref_filter {
 	void *cb_data;
 };
 
-int read_ref(const char *ref, unsigned char *sha1)
+int read_ref(const char *refname, unsigned char *sha1)
 {
-	if (resolve_ref(ref, sha1, 1, NULL))
+	if (resolve_ref(refname, sha1, 1, NULL))
 		return 0;
 	return -1;
 }
@@ -629,23 +632,23 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
 	return fn(entry->name + trim, entry->sha1, entry->flag, cb_data);
 }
 
-static int filter_refs(const char *ref, const unsigned char *sha, int flags,
+static int filter_refs(const char *refname, const unsigned char *sha, int flags,
 	void *data)
 {
 	struct ref_filter *filter = (struct ref_filter *)data;
-	if (fnmatch(filter->pattern, ref, 0))
+	if (fnmatch(filter->pattern, refname, 0))
 		return 0;
-	return filter->fn(ref, sha, flags, filter->cb_data);
+	return filter->fn(refname, sha, flags, filter->cb_data);
 }
 
-int peel_ref(const char *ref, unsigned char *sha1)
+int peel_ref(const char *refname, unsigned char *sha1)
 {
 	int flag;
 	unsigned char base[20];
 	struct object *o;
 
-	if (current_ref && (current_ref->name == ref
-		|| !strcmp(current_ref->name, ref))) {
+	if (current_ref && (current_ref->name == refname
+		|| !strcmp(current_ref->name, refname))) {
 		if (current_ref->flag & REF_KNOWS_PEELED) {
 			hashcpy(sha1, current_ref->peeled);
 			return 0;
@@ -654,12 +657,12 @@ int peel_ref(const char *ref, unsigned char *sha1)
 		goto fallback;
 	}
 
-	if (!resolve_ref(ref, base, 1, &flag))
+	if (!resolve_ref(refname, base, 1, &flag))
 		return -1;
 
 	if ((flag & REF_ISPACKED)) {
 		struct ref_array *array = get_packed_refs(NULL);
-		struct ref_entry *r = search_ref_array(array, ref);
+		struct ref_entry *r = search_ref_array(array, refname);
 
 		if (r != NULL && r->flag & REF_KNOWS_PEELED) {
 			hashcpy(sha1, r->peeled);
@@ -670,7 +673,7 @@ int peel_ref(const char *ref, unsigned char *sha1)
 fallback:
 	o = parse_object(base);
 	if (o && o->type == OBJ_TAG) {
-		o = deref_tag(o, ref, 0);
+		o = deref_tag(o, refname, 0);
 		if (o) {
 			hashcpy(sha1, o->sha1);
 			return 0;
@@ -900,16 +903,16 @@ static inline int bad_ref_char(int ch)
 }
 
 /*
- * Try to read one refname component from the front of ref.  Return
+ * Try to read one refname component from the front of refname.  Return
  * the length of the component found, or -1 if the component is not
  * legal.
  */
-static int check_refname_component(const char *ref, int flags)
+static int check_refname_component(const char *refname, int flags)
 {
 	const char *cp;
 	char last = '\0';
 
-	for (cp = ref; ; cp++) {
+	for (cp = refname; ; cp++) {
 		char ch = *cp;
 		if (ch == '\0' || ch == '/')
 			break;
@@ -921,34 +924,34 @@ static int check_refname_component(const char *ref, int flags)
 			return -1; /* Refname contains "@{". */
 		last = ch;
 	}
-	if (cp == ref)
+	if (cp == refname)
 		return -1; /* Component has zero length. */
-	if (ref[0] == '.') {
+	if (refname[0] == '.') {
 		if (!(flags & REFNAME_DOT_COMPONENT))
 			return -1; /* Component starts with '.'. */
 		/*
 		 * Even if leading dots are allowed, don't allow "."
 		 * as a component (".." is prevented by a rule above).
 		 */
-		if (ref[1] == '\0')
+		if (refname[1] == '\0')
 			return -1; /* Component equals ".". */
 	}
-	if (cp - ref >= 5 && !memcmp(cp - 5, ".lock", 5))
+	if (cp - refname >= 5 && !memcmp(cp - 5, ".lock", 5))
 		return -1; /* Refname ends with ".lock". */
-	return cp - ref;
+	return cp - refname;
 }
 
-int check_refname_format(const char *ref, int flags)
+int check_refname_format(const char *refname, int flags)
 {
 	int component_len, component_count = 0;
 
 	while (1) {
 		/* We are at the start of a path component. */
-		component_len = check_refname_component(ref, flags);
+		component_len = check_refname_component(refname, flags);
 		if (component_len < 0) {
 			if ((flags & REFNAME_REFSPEC_PATTERN) &&
-					ref[0] == '*' &&
-					(ref[1] == '\0' || ref[1] == '/')) {
+					refname[0] == '*' &&
+					(refname[1] == '\0' || refname[1] == '/')) {
 				/* Accept one wildcard as a full refname component. */
 				flags &= ~REFNAME_REFSPEC_PATTERN;
 				component_len = 1;
@@ -957,13 +960,13 @@ int check_refname_format(const char *ref, int flags)
 			}
 		}
 		component_count++;
-		if (ref[component_len] == '\0')
+		if (refname[component_len] == '\0')
 			break;
 		/* Skip to next component. */
-		ref += component_len + 1;
+		refname += component_len + 1;
 	}
 
-	if (ref[component_len - 1] == '.')
+	if (refname[component_len - 1] == '.')
 		return -1; /* Refname ends with '.'. */
 	if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)
 		return -1; /* Refname has only one component. */
@@ -1046,22 +1049,22 @@ static int remove_empty_directories(const char *file)
 	return result;
 }
 
-static int is_refname_available(const char *ref, const char *oldref,
+static int is_refname_available(const char *refname, const char *oldrefname,
 				struct ref_array *array, int quiet)
 {
-	int i, namlen = strlen(ref); /* e.g. 'foo/bar' */
+	int i, namlen = strlen(refname); /* e.g. 'foo/bar' */
 	for (i = 0; i < array->nr; i++ ) {
 		struct ref_entry *entry = array->refs[i];
 		/* entry->name could be 'foo' or 'foo/bar/baz' */
-		if (!oldref || strcmp(oldref, entry->name)) {
+		if (!oldrefname || strcmp(oldrefname, entry->name)) {
 			int len = strlen(entry->name);
 			int cmplen = (namlen < len) ? namlen : len;
-			const char *lead = (namlen < len) ? entry->name : ref;
-			if (!strncmp(ref, entry->name, cmplen) &&
+			const char *lead = (namlen < len) ? entry->name : refname;
+			if (!strncmp(refname, entry->name, cmplen) &&
 			    lead[cmplen] == '/') {
 				if (!quiet)
 					error("'%s' exists; cannot create '%s'",
-					      entry->name, ref);
+					      entry->name, refname);
 				return 0;
 			}
 		}
@@ -1069,10 +1072,12 @@ static int is_refname_available(const char *ref, const char *oldref,
 	return 1;
 }
 
-static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char *old_sha1, int flags, int *type_p)
+static struct ref_lock *lock_ref_sha1_basic(const char *refname,
+					    const unsigned char *old_sha1,
+					    int flags, int *type_p)
 {
 	char *ref_file;
-	const char *orig_ref = ref;
+	const char *orig_refname = refname;
 	struct ref_lock *lock;
 	int last_errno = 0;
 	int type, lflags;
@@ -1082,27 +1087,27 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
 	lock = xcalloc(1, sizeof(struct ref_lock));
 	lock->lock_fd = -1;
 
-	ref = resolve_ref(ref, lock->old_sha1, mustexist, &type);
-	if (!ref && errno == EISDIR) {
+	refname = resolve_ref(refname, lock->old_sha1, mustexist, &type);
+	if (!refname && errno == EISDIR) {
 		/* we are trying to lock foo but we used to
 		 * have foo/bar which now does not exist;
 		 * it is normal for the empty directory 'foo'
 		 * to remain.
 		 */
-		ref_file = git_path("%s", orig_ref);
+		ref_file = git_path("%s", orig_refname);
 		if (remove_empty_directories(ref_file)) {
 			last_errno = errno;
-			error("there are still refs under '%s'", orig_ref);
+			error("there are still refs under '%s'", orig_refname);
 			goto error_return;
 		}
-		ref = resolve_ref(orig_ref, lock->old_sha1, mustexist, &type);
+		refname = resolve_ref(orig_refname, lock->old_sha1, mustexist, &type);
 	}
 	if (type_p)
 	    *type_p = type;
-	if (!ref) {
+	if (!refname) {
 		last_errno = errno;
 		error("unable to resolve reference %s: %s",
-			orig_ref, strerror(errno));
+			orig_refname, strerror(errno));
 		goto error_return;
 	}
 	missing = is_null_sha1(lock->old_sha1);
@@ -1112,7 +1117,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
 	 * name is a proper prefix of our refname.
 	 */
 	if (missing &&
-	     !is_refname_available(ref, NULL, get_packed_refs(NULL), 0)) {
+	     !is_refname_available(refname, NULL, get_packed_refs(NULL), 0)) {
 		last_errno = ENOTDIR;
 		goto error_return;
 	}
@@ -1121,12 +1126,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
 
 	lflags = LOCK_DIE_ON_ERROR;
 	if (flags & REF_NODEREF) {
-		ref = orig_ref;
+		refname = orig_refname;
 		lflags |= LOCK_NODEREF;
 	}
-	lock->ref_name = xstrdup(ref);
-	lock->orig_ref_name = xstrdup(orig_ref);
-	ref_file = git_path("%s", ref);
+	lock->ref_name = xstrdup(refname);
+	lock->orig_ref_name = xstrdup(orig_refname);
+	ref_file = git_path("%s", refname);
 	if (missing)
 		lock->force_write = 1;
 	if ((flags & REF_NODEREF) && (type & REF_ISSYMREF))
@@ -1147,20 +1152,21 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
 	return NULL;
 }
 
-struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
+struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1)
 {
 	char refpath[PATH_MAX];
-	if (check_refname_format(ref, 0))
+	if (check_refname_format(refname, 0))
 		return NULL;
-	strcpy(refpath, mkpath("refs/%s", ref));
+	strcpy(refpath, mkpath("refs/%s", refname));
 	return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL);
 }
 
-struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int flags)
+struct ref_lock *lock_any_ref_for_update(const char *refname,
+					 const unsigned char *old_sha1, int flags)
 {
-	if (check_refname_format(ref, REFNAME_ALLOW_ONELEVEL))
+	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
 		return NULL;
-	return lock_ref_sha1_basic(ref, old_sha1, flags, NULL);
+	return lock_ref_sha1_basic(refname, old_sha1, flags, NULL);
 }
 
 static struct lock_file packlock;
@@ -1246,30 +1252,30 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
  */
 #define TMP_RENAMED_LOG  "logs/refs/.tmp-renamed-log"
 
-int rename_ref(const char *oldref, const char *newref, const char *logmsg)
+int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
 {
 	static const char renamed_ref[] = "RENAMED-REF";
 	unsigned char sha1[20], orig_sha1[20];
 	int flag = 0, logmoved = 0;
 	struct ref_lock *lock;
 	struct stat loginfo;
-	int log = !lstat(git_path("logs/%s", oldref), &loginfo);
+	int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
 	const char *symref = NULL;
 
 	if (log && S_ISLNK(loginfo.st_mode))
-		return error("reflog for %s is a symlink", oldref);
+		return error("reflog for %s is a symlink", oldrefname);
 
-	symref = resolve_ref(oldref, orig_sha1, 1, &flag);
+	symref = resolve_ref(oldrefname, orig_sha1, 1, &flag);
 	if (flag & REF_ISSYMREF)
 		return error("refname %s is a symbolic ref, renaming it is not supported",
-			oldref);
+			oldrefname);
 	if (!symref)
-		return error("refname %s not found", oldref);
+		return error("refname %s not found", oldrefname);
 
-	if (!is_refname_available(newref, oldref, get_packed_refs(NULL), 0))
+	if (!is_refname_available(newrefname, oldrefname, get_packed_refs(NULL), 0))
 		return 1;
 
-	if (!is_refname_available(newref, oldref, get_loose_refs(NULL), 0))
+	if (!is_refname_available(newrefname, oldrefname, get_loose_refs(NULL), 0))
 		return 1;
 
 	lock = lock_ref_sha1_basic(renamed_ref, NULL, 0, NULL);
@@ -1279,71 +1285,71 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
 	if (write_ref_sha1(lock, orig_sha1, logmsg))
 		return error("unable to save current sha1 in %s", renamed_ref);
 
-	if (log && rename(git_path("logs/%s", oldref), git_path(TMP_RENAMED_LOG)))
+	if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG)))
 		return error("unable to move logfile logs/%s to "TMP_RENAMED_LOG": %s",
-			oldref, strerror(errno));
+			oldrefname, strerror(errno));
 
-	if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
-		error("unable to delete old %s", oldref);
+	if (delete_ref(oldrefname, orig_sha1, REF_NODEREF)) {
+		error("unable to delete old %s", oldrefname);
 		goto rollback;
 	}
 
-	if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1, REF_NODEREF)) {
+	if (resolve_ref(newrefname, sha1, 1, &flag) && delete_ref(newrefname, sha1, REF_NODEREF)) {
 		if (errno==EISDIR) {
-			if (remove_empty_directories(git_path("%s", newref))) {
-				error("Directory not empty: %s", newref);
+			if (remove_empty_directories(git_path("%s", newrefname))) {
+				error("Directory not empty: %s", newrefname);
 				goto rollback;
 			}
 		} else {
-			error("unable to delete existing %s", newref);
+			error("unable to delete existing %s", newrefname);
 			goto rollback;
 		}
 	}
 
-	if (log && safe_create_leading_directories(git_path("logs/%s", newref))) {
-		error("unable to create directory for %s", newref);
+	if (log && safe_create_leading_directories(git_path("logs/%s", newrefname))) {
+		error("unable to create directory for %s", newrefname);
 		goto rollback;
 	}
 
  retry:
-	if (log && rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newref))) {
+	if (log && rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname))) {
 		if (errno==EISDIR || errno==ENOTDIR) {
 			/*
 			 * rename(a, b) when b is an existing
 			 * directory ought to result in ISDIR, but
 			 * Solaris 5.8 gives ENOTDIR.  Sheesh.
 			 */
-			if (remove_empty_directories(git_path("logs/%s", newref))) {
-				error("Directory not empty: logs/%s", newref);
+			if (remove_empty_directories(git_path("logs/%s", newrefname))) {
+				error("Directory not empty: logs/%s", newrefname);
 				goto rollback;
 			}
 			goto retry;
 		} else {
 			error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
-				newref, strerror(errno));
+				newrefname, strerror(errno));
 			goto rollback;
 		}
 	}
 	logmoved = log;
 
-	lock = lock_ref_sha1_basic(newref, NULL, 0, NULL);
+	lock = lock_ref_sha1_basic(newrefname, NULL, 0, NULL);
 	if (!lock) {
-		error("unable to lock %s for update", newref);
+		error("unable to lock %s for update", newrefname);
 		goto rollback;
 	}
 	lock->force_write = 1;
 	hashcpy(lock->old_sha1, orig_sha1);
 	if (write_ref_sha1(lock, orig_sha1, logmsg)) {
-		error("unable to write current sha1 into %s", newref);
+		error("unable to write current sha1 into %s", newrefname);
 		goto rollback;
 	}
 
 	return 0;
 
  rollback:
-	lock = lock_ref_sha1_basic(oldref, NULL, 0, NULL);
+	lock = lock_ref_sha1_basic(oldrefname, NULL, 0, NULL);
 	if (!lock) {
-		error("unable to lock %s for rollback", oldref);
+		error("unable to lock %s for rollback", oldrefname);
 		goto rollbacklog;
 	}
 
@@ -1351,17 +1357,17 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
 	flag = log_all_ref_updates;
 	log_all_ref_updates = 0;
 	if (write_ref_sha1(lock, orig_sha1, NULL))
-		error("unable to write current sha1 into %s", oldref);
+		error("unable to write current sha1 into %s", oldrefname);
 	log_all_ref_updates = flag;
 
  rollbacklog:
-	if (logmoved && rename(git_path("logs/%s", newref), git_path("logs/%s", oldref)))
+	if (logmoved && rename(git_path("logs/%s", newrefname), git_path("logs/%s", oldrefname)))
 		error("unable to restore logfile %s from %s: %s",
-			oldref, newref, strerror(errno));
+			oldrefname, newrefname, strerror(errno));
 	if (!logmoved && log &&
-	    rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", oldref)))
+	    rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", oldrefname)))
 		error("unable to restore logfile %s from "TMP_RENAMED_LOG": %s",
-			oldref, strerror(errno));
+			oldrefname, strerror(errno));
 
 	return 1;
 }
@@ -1418,16 +1424,16 @@ static int copy_msg(char *buf, const char *msg)
 	return cp - buf;
 }
 
-int log_ref_setup(const char *ref_name, char *logfile, int bufsize)
+int log_ref_setup(const char *refname, char *logfile, int bufsize)
 {
 	int logfd, oflags = O_APPEND | O_WRONLY;
 
-	git_snpath(logfile, bufsize, "logs/%s", ref_name);
+	git_snpath(logfile, bufsize, "logs/%s", refname);
 	if (log_all_ref_updates &&
-	    (!prefixcmp(ref_name, "refs/heads/") ||
-	     !prefixcmp(ref_name, "refs/remotes/") ||
-	     !prefixcmp(ref_name, "refs/notes/") ||
-	     !strcmp(ref_name, "HEAD"))) {
+	    (!prefixcmp(refname, "refs/heads/") ||
+	     !prefixcmp(refname, "refs/remotes/") ||
+	     !prefixcmp(refname, "refs/notes/") ||
+	     !strcmp(refname, "HEAD"))) {
 		if (safe_create_leading_directories(logfile) < 0)
 			return error("unable to create directory for %s",
 				     logfile);
@@ -1457,7 +1463,7 @@ int log_ref_setup(const char *ref_name, char *logfile, int bufsize)
 	return 0;
 }
 
-static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
+static int log_ref_write(const char *refname, const unsigned char *old_sha1,
 			 const unsigned char *new_sha1, const char *msg)
 {
 	int logfd, result, written, oflags = O_APPEND | O_WRONLY;
@@ -1470,7 +1476,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
 	if (log_all_ref_updates < 0)
 		log_all_ref_updates = !is_bare_repository();
 
-	result = log_ref_setup(ref_name, log_file, sizeof(log_file));
+	result = log_ref_setup(refname, log_file, sizeof(log_file));
 	if (result)
 		return result;
 
@@ -1641,7 +1647,9 @@ static char *ref_msg(const char *line, const char *endp)
 	return xmemdupz(line, ep - line);
 }
 
-int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *sha1, char **msg, unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
+int read_ref_at(const char *refname, unsigned long at_time, int cnt,
+		unsigned char *sha1, char **msg,
+		unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
 {
 	const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec;
 	char *tz_c;
@@ -1652,7 +1660,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
 	void *log_mapped;
 	size_t mapsz;
 
-	logfile = git_path("logs/%s", ref);
+	logfile = git_path("logs/%s", refname);
 	logfd = open(logfile, O_RDONLY, 0);
 	if (logfd < 0)
 		die_errno("Unable to read log '%s'", logfile);
@@ -1745,14 +1753,14 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
 	return 1;
 }
 
-int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs, void *cb_data)
+int for_each_recent_reflog_ent(const char *refname, each_reflog_ent_fn fn, long ofs, void *cb_data)
 {
 	const char *logfile;
 	FILE *logfp;
 	struct strbuf sb = STRBUF_INIT;
 	int ret = 0;
 
-	logfile = git_path("logs/%s", ref);
+	logfile = git_path("logs/%s", refname);
 	logfp = fopen(logfile, "r");
 	if (!logfp)
 		return -1;
@@ -1803,9 +1811,9 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
 	return ret;
 }
 
-int for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
+int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data)
 {
-	return for_each_recent_reflog_ent(ref, fn, 0, cb_data);
+	return for_each_recent_reflog_ent(refname, fn, 0, cb_data);
 }
 
 static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data)
@@ -1925,7 +1933,7 @@ static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
 	return;
 }
 
-char *shorten_unambiguous_ref(const char *ref, int strict)
+char *shorten_unambiguous_ref(const char *refname, int strict)
 {
 	int i;
 	static char **scanf_fmts;
@@ -1954,10 +1962,10 @@ char *shorten_unambiguous_ref(const char *ref, int strict)
 
 	/* bail out if there are no rules */
 	if (!nr_rules)
-		return xstrdup(ref);
+		return xstrdup(refname);
 
-	/* buffer for scanf result, at most ref must fit */
-	short_name = xstrdup(ref);
+	/* buffer for scanf result, at most refname must fit */
+	short_name = xstrdup(refname);
 
 	/* skip first rule, it will always match */
 	for (i = nr_rules - 1; i > 0 ; --i) {
@@ -1965,7 +1973,7 @@ char *shorten_unambiguous_ref(const char *ref, int strict)
 		int rules_to_fail = i;
 		int short_name_len;
 
-		if (1 != sscanf(ref, scanf_fmts[i], short_name))
+		if (1 != sscanf(refname, scanf_fmts[i], short_name))
 			continue;
 
 		short_name_len = strlen(short_name);
@@ -2010,5 +2018,5 @@ char *shorten_unambiguous_ref(const char *ref, int strict)
 	}
 
 	free(short_name);
-	return xstrdup(ref);
+	return xstrdup(refname);
 }
diff --git a/refs.h b/refs.h
index f439c54eb2..13e2aa3399 100644
--- a/refs.h
+++ b/refs.h
@@ -59,14 +59,16 @@ extern void add_extra_ref(const char *refname, const unsigned char *sha1, int fl
 extern void clear_extra_refs(void);
 extern int ref_exists(const char *);
 
-extern int peel_ref(const char *, unsigned char *);
+extern int peel_ref(const char *refname, unsigned char *sha1);
 
 /** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
-extern struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1);
+extern struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1);
 
 /** Locks any ref (for 'HEAD' type refs). */
 #define REF_NODEREF	0x01
-extern struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int flags);
+extern struct ref_lock *lock_any_ref_for_update(const char *refname,
+						const unsigned char *old_sha1,
+						int flags);
 
 /** Close the file descriptor owned by a lock and return the status */
 extern int close_ref(struct ref_lock *lock);
@@ -92,12 +94,14 @@ extern void invalidate_ref_cache(const char *submodule);
 int log_ref_setup(const char *ref_name, char *logfile, int bufsize);
 
 /** Reads log for the value of ref during at_time. **/
-extern int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *sha1, char **msg, unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);
+extern int read_ref_at(const char *refname, unsigned long at_time, int cnt,
+		       unsigned char *sha1, char **msg,
+		       unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);
 
 /* iterate over reflog entries */
 typedef int each_reflog_ent_fn(unsigned char *osha1, unsigned char *nsha1, const char *, unsigned long, int, const char *, void *);
-int for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data);
-int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long, void *cb_data);
+int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data);
+int for_each_recent_reflog_ent(const char *refname, each_reflog_ent_fn fn, long, void *cb_data);
 
 /*
  * Calls the specified function for each reflog file until it returns nonzero,
@@ -110,9 +114,9 @@ extern int for_each_reflog(each_ref_fn, void *);
 #define REFNAME_DOT_COMPONENT 4
 
 /*
- * Return 0 iff ref has the correct format for a refname according to
- * the rules described in Documentation/git-check-ref-format.txt.  If
- * REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
+ * Return 0 iff refname has the correct format for a refname according
+ * to the rules described in Documentation/git-check-ref-format.txt.
+ * If REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
  * reference names.  If REFNAME_REFSPEC_PATTERN is set in flags, then
  * allow a "*" wildcard character in place of one of the name
  * components.  No leading or repeated slashes are accepted.  If
@@ -120,10 +124,10 @@ extern int for_each_reflog(each_ref_fn, void *);
  * components to start with "." (but not a whole component equal to
  * "." or "..").
  */
-extern int check_refname_format(const char *ref, int flags);
+extern int check_refname_format(const char *refname, int flags);
 
 extern const char *prettify_refname(const char *refname);
-extern char *shorten_unambiguous_ref(const char *ref, int strict);
+extern char *shorten_unambiguous_ref(const char *refname, int strict);
 
 /** rename ref, return 0 on success **/
 extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);

From 349e88f02bd8ce2377cee379c3e9b85381f67ede Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:13 +0200
Subject: [PATCH 2213/3720] refs: rename parameters result -> sha1

Try consistently to use the name "sha1" for parameters to which a SHA1
will be stored.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 16 ++++++++--------
 refs.h |  2 +-
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/refs.c b/refs.c
index a5d560c4e1..87c8913e9d 100644
--- a/refs.c
+++ b/refs.c
@@ -398,7 +398,7 @@ static struct ref_array *get_loose_refs(const char *submodule)
 #define MAXREFLEN (1024)
 
 static int resolve_gitlink_packed_ref(char *name, int pathlen,
-				      const char *refname, unsigned char *result)
+				      const char *refname, unsigned char *sha1)
 {
 	int retval = -1;
 	struct ref_entry *ref;
@@ -406,14 +406,14 @@ static int resolve_gitlink_packed_ref(char *name, int pathlen,
 
 	ref = search_ref_array(array, refname);
 	if (ref != NULL) {
-		memcpy(result, ref->sha1, 20);
+		memcpy(sha1, ref->sha1, 20);
 		retval = 0;
 	}
 	return retval;
 }
 
 static int resolve_gitlink_ref_recursive(char *name, int pathlen,
-					 const char *refname, unsigned char *result,
+					 const char *refname, unsigned char *sha1,
 					 int recursion)
 {
 	int fd, len = strlen(refname);
@@ -424,7 +424,7 @@ static int resolve_gitlink_ref_recursive(char *name, int pathlen,
 	memcpy(name + pathlen, refname, len+1);
 	fd = open(name, O_RDONLY);
 	if (fd < 0)
-		return resolve_gitlink_packed_ref(name, pathlen, refname, result);
+		return resolve_gitlink_packed_ref(name, pathlen, refname, sha1);
 
 	len = read(fd, buffer, sizeof(buffer)-1);
 	close(fd);
@@ -435,7 +435,7 @@ static int resolve_gitlink_ref_recursive(char *name, int pathlen,
 	buffer[len] = 0;
 
 	/* Was it a detached head or an old-fashioned symlink? */
-	if (!get_sha1_hex(buffer, result))
+	if (!get_sha1_hex(buffer, sha1))
 		return 0;
 
 	/* Symref? */
@@ -445,10 +445,10 @@ static int resolve_gitlink_ref_recursive(char *name, int pathlen,
 	while (isspace(*p))
 		p++;
 
-	return resolve_gitlink_ref_recursive(name, pathlen, p, result, recursion+1);
+	return resolve_gitlink_ref_recursive(name, pathlen, p, sha1, recursion+1);
 }
 
-int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *result)
+int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
 {
 	int len = strlen(path), retval;
 	char *gitdir;
@@ -472,7 +472,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re
 	}
 	gitdir[len] = '/';
 	gitdir[++len] = '\0';
-	retval = resolve_gitlink_ref_recursive(gitdir, len, refname, result, 0);
+	retval = resolve_gitlink_ref_recursive(gitdir, len, refname, sha1, 0);
 	free(gitdir);
 	return retval;
 }
diff --git a/refs.h b/refs.h
index 13e2aa3399..c6b87495e6 100644
--- a/refs.h
+++ b/refs.h
@@ -133,7 +133,7 @@ extern char *shorten_unambiguous_ref(const char *refname, int strict);
 extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);
 
 /** resolve ref in nested "gitlink" repository */
-extern int resolve_gitlink_ref(const char *name, const char *refname, unsigned char *result);
+extern int resolve_gitlink_ref(const char *name, const char *refname, unsigned char *sha1);
 
 /** lock a ref and then write its file */
 enum action_on_err { MSG_ON_ERR, DIE_ON_ERR, QUIET_ON_ERR };

From 34e31bae6f3f5eec465cade584520c576b1b0d4e Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:14 +0200
Subject: [PATCH 2214/3720] clear_ref_array(): rename from free_ref_array()

Rename the function since it doesn't actually free the array object
that is passed to it.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/refs.c b/refs.c
index 87c8913e9d..30e505a9d3 100644
--- a/refs.c
+++ b/refs.c
@@ -149,7 +149,7 @@ static struct ref_entry *current_ref;
 
 static struct ref_array extra_refs;
 
-static void free_ref_array(struct ref_array *array)
+static void clear_ref_array(struct ref_array *array)
 {
 	int i;
 	for (i = 0; i < array->nr; i++)
@@ -162,14 +162,14 @@ static void free_ref_array(struct ref_array *array)
 static void clear_packed_ref_cache(struct ref_cache *refs)
 {
 	if (refs->did_packed)
-		free_ref_array(&refs->packed);
+		clear_ref_array(&refs->packed);
 	refs->did_packed = 0;
 }
 
 static void clear_loose_ref_cache(struct ref_cache *refs)
 {
 	if (refs->did_loose)
-		free_ref_array(&refs->loose);
+		clear_ref_array(&refs->loose);
 	refs->did_loose = 0;
 }
 
@@ -256,7 +256,7 @@ void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
 
 void clear_extra_refs(void)
 {
-	free_ref_array(&extra_refs);
+	clear_ref_array(&extra_refs);
 }
 
 static struct ref_array *get_packed_refs(const char *submodule)

From 31c7d82200232d7589824fc25d5b2c754166ccdd Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:15 +0200
Subject: [PATCH 2215/3720] is_refname_available(): remove the "quiet" argument

quiet was always set to 0, so get rid of it.  Add a function docstring
for good measure.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/refs.c b/refs.c
index 30e505a9d3..597800a5ed 100644
--- a/refs.c
+++ b/refs.c
@@ -1049,8 +1049,15 @@ static int remove_empty_directories(const char *file)
 	return result;
 }
 
+/*
+ * Return true iff a reference named refname could be created without
+ * conflicting with the name of an existing reference.  If oldrefname
+ * is non-NULL, ignore potential conflicts with oldrefname (e.g.,
+ * because oldrefname is scheduled for deletion in the same
+ * operation).
+ */
 static int is_refname_available(const char *refname, const char *oldrefname,
-				struct ref_array *array, int quiet)
+				struct ref_array *array)
 {
 	int i, namlen = strlen(refname); /* e.g. 'foo/bar' */
 	for (i = 0; i < array->nr; i++ ) {
@@ -1062,9 +1069,8 @@ static int is_refname_available(const char *refname, const char *oldrefname,
 			const char *lead = (namlen < len) ? entry->name : refname;
 			if (!strncmp(refname, entry->name, cmplen) &&
 			    lead[cmplen] == '/') {
-				if (!quiet)
-					error("'%s' exists; cannot create '%s'",
-					      entry->name, refname);
+				error("'%s' exists; cannot create '%s'",
+				      entry->name, refname);
 				return 0;
 			}
 		}
@@ -1117,7 +1123,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
 	 * name is a proper prefix of our refname.
 	 */
 	if (missing &&
-	     !is_refname_available(refname, NULL, get_packed_refs(NULL), 0)) {
+	     !is_refname_available(refname, NULL, get_packed_refs(NULL))) {
 		last_errno = ENOTDIR;
 		goto error_return;
 	}
@@ -1272,10 +1278,10 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
 	if (!symref)
 		return error("refname %s not found", oldrefname);
 
-	if (!is_refname_available(newrefname, oldrefname, get_packed_refs(NULL), 0))
+	if (!is_refname_available(newrefname, oldrefname, get_packed_refs(NULL)))
 		return 1;
 
-	if (!is_refname_available(newrefname, oldrefname, get_loose_refs(NULL), 0))
+	if (!is_refname_available(newrefname, oldrefname, get_loose_refs(NULL)))
 		return 1;
 
 	lock = lock_ref_sha1_basic(renamed_ref, NULL, 0, NULL);

From 167f91eac9d5dfb42e05645cafa9a26e6745cd85 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:16 +0200
Subject: [PATCH 2216/3720] parse_ref_line(): add docstring

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/refs.c b/refs.c
index 597800a5ed..af34c3b5ec 100644
--- a/refs.c
+++ b/refs.c
@@ -21,6 +21,11 @@ struct ref_array {
 	struct ref_entry **refs;
 };
 
+/*
+ * Parse one line from a packed-refs file.  Write the SHA1 to sha1.
+ * Return a pointer to the refname within the line (null-terminated),
+ * or NULL if there was a problem.
+ */
 static const char *parse_ref_line(char *line, unsigned char *sha1)
 {
 	/*

From 67d806cd3a73ce0595f8aee80a43858c83d0b04c Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:17 +0200
Subject: [PATCH 2217/3720] add_ref(): add docstring

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/refs.c b/refs.c
index af34c3b5ec..ea0f598efe 100644
--- a/refs.c
+++ b/refs.c
@@ -54,6 +54,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 	return line;
 }
 
+/* Add a ref_entry to the end of the ref_array (unsorted). */
 static void add_ref(const char *refname, const unsigned char *sha1,
 		    int flag, struct ref_array *refs,
 		    struct ref_entry **new_entry)

From 98441d5ebef5dc512366fedd07f274d2e401e08b Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:18 +0200
Subject: [PATCH 2218/3720] is_dup_ref(): extract function from
 sort_ref_array()

Giving it a name makes the code easier to understand.  And the new
function will be convenient later when it has to be called from
multiple places.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/refs.c b/refs.c
index ea0f598efe..7417f9a5af 100644
--- a/refs.c
+++ b/refs.c
@@ -84,6 +84,25 @@ static int ref_entry_cmp(const void *a, const void *b)
 	return strcmp(one->name, two->name);
 }
 
+/*
+ * Emit a warning and return true iff ref1 and ref2 have the same name
+ * and the same sha1.  Die if they have the same name but different
+ * sha1s.
+ */
+static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2)
+{
+	if (!strcmp(ref1->name, ref2->name)) {
+		/* Duplicate name; make sure that the SHA1s match: */
+		if (hashcmp(ref1->sha1, ref2->sha1))
+			die("Duplicated ref, and SHA1s don't match: %s",
+			    ref1->name);
+		warning("Duplicated ref: %s", ref1->name);
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
 static void sort_ref_array(struct ref_array *array)
 {
 	int i = 0, j = 1;
@@ -98,11 +117,7 @@ static void sort_ref_array(struct ref_array *array)
 	for (; j < array->nr; j++) {
 		struct ref_entry *a = array->refs[i];
 		struct ref_entry *b = array->refs[j];
-		if (!strcmp(a->name, b->name)) {
-			if (hashcmp(a->sha1, b->sha1))
-				die("Duplicated ref, and SHA1s don't match: %s",
-				    a->name);
-			warning("Duplicated ref: %s", a->name);
+		if (is_dup_ref(a, b)) {
 			free(b);
 			continue;
 		}

From 02667f06dcd80edc200498ed3a1cf0b59eb51cb6 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:19 +0200
Subject: [PATCH 2219/3720] refs: change signatures of get_packed_refs() and
 get_loose_refs()

Change get_packed_refs() and get_loose_refs() to take a (struct
ref_cache *) instead of the name of the submodule.

Change get_ref_dir() to take a submodule name (i.e., "" for the main
module) rather than a submodule pointer (i.e., NULL for the main
module) so that refs->name can be used as its argument.  (In a moment
this function will also be changed to take a (struct ref_cache *),
too.)

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 36 +++++++++++++++++-------------------
 1 file changed, 17 insertions(+), 19 deletions(-)

diff --git a/refs.c b/refs.c
index 7417f9a5af..9051b9f8c2 100644
--- a/refs.c
+++ b/refs.c
@@ -280,16 +280,14 @@ void clear_extra_refs(void)
 	clear_ref_array(&extra_refs);
 }
 
-static struct ref_array *get_packed_refs(const char *submodule)
+static struct ref_array *get_packed_refs(struct ref_cache *refs)
 {
-	struct ref_cache *refs = get_ref_cache(submodule);
-
 	if (!refs->did_packed) {
 		const char *packed_refs_file;
 		FILE *f;
 
-		if (submodule)
-			packed_refs_file = git_path_submodule(submodule, "packed-refs");
+		if (*refs->name)
+			packed_refs_file = git_path_submodule(refs->name, "packed-refs");
 		else
 			packed_refs_file = git_path("packed-refs");
 		f = fopen(packed_refs_file, "r");
@@ -308,7 +306,7 @@ static void get_ref_dir(const char *submodule, const char *base,
 	DIR *dir;
 	const char *path;
 
-	if (submodule)
+	if (*submodule)
 		path = git_path_submodule(submodule, "%s", base);
 	else
 		path = git_path("%s", base);
@@ -402,12 +400,10 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
 	for_each_rawref(warn_if_dangling_symref, &data);
 }
 
-static struct ref_array *get_loose_refs(const char *submodule)
+static struct ref_array *get_loose_refs(struct ref_cache *refs)
 {
-	struct ref_cache *refs = get_ref_cache(submodule);
-
 	if (!refs->did_loose) {
-		get_ref_dir(submodule, "refs", &refs->loose);
+		get_ref_dir(refs->name, "refs", &refs->loose);
 		sort_ref_array(&refs->loose);
 		refs->did_loose = 1;
 	}
@@ -423,7 +419,7 @@ static int resolve_gitlink_packed_ref(char *name, int pathlen,
 {
 	int retval = -1;
 	struct ref_entry *ref;
-	struct ref_array *array = get_packed_refs(name);
+	struct ref_array *array = get_packed_refs(get_ref_cache(name));
 
 	ref = search_ref_array(array, refname);
 	if (ref != NULL) {
@@ -504,7 +500,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
  */
 static int get_packed_ref(const char *refname, unsigned char *sha1)
 {
-	struct ref_array *packed = get_packed_refs(NULL);
+	struct ref_array *packed = get_packed_refs(get_ref_cache(NULL));
 	struct ref_entry *entry = search_ref_array(packed, refname);
 	if (entry) {
 		hashcpy(sha1, entry->sha1);
@@ -682,7 +678,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
 		return -1;
 
 	if ((flag & REF_ISPACKED)) {
-		struct ref_array *array = get_packed_refs(NULL);
+		struct ref_array *array = get_packed_refs(get_ref_cache(NULL));
 		struct ref_entry *r = search_ref_array(array, refname);
 
 		if (r != NULL && r->flag & REF_KNOWS_PEELED) {
@@ -707,8 +703,9 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
 			   int trim, int flags, void *cb_data)
 {
 	int retval = 0, i, p = 0, l = 0;
-	struct ref_array *packed = get_packed_refs(submodule);
-	struct ref_array *loose = get_loose_refs(submodule);
+	struct ref_cache *refs = get_ref_cache(submodule);
+	struct ref_array *packed = get_packed_refs(refs);
+	struct ref_array *loose = get_loose_refs(refs);
 
 	struct ref_array *extra = &extra_refs;
 
@@ -1144,7 +1141,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
 	 * name is a proper prefix of our refname.
 	 */
 	if (missing &&
-	     !is_refname_available(refname, NULL, get_packed_refs(NULL))) {
+	     !is_refname_available(refname, NULL, get_packed_refs(get_ref_cache(NULL)))) {
 		last_errno = ENOTDIR;
 		goto error_return;
 	}
@@ -1204,7 +1201,7 @@ static int repack_without_ref(const char *refname)
 	struct ref_entry *ref;
 	int fd, i;
 
-	packed = get_packed_refs(NULL);
+	packed = get_packed_refs(get_ref_cache(NULL));
 	ref = search_ref_array(packed, refname);
 	if (ref == NULL)
 		return 0;
@@ -1288,6 +1285,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
 	struct stat loginfo;
 	int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
 	const char *symref = NULL;
+	struct ref_cache *refs = get_ref_cache(NULL);
 
 	if (log && S_ISLNK(loginfo.st_mode))
 		return error("reflog for %s is a symlink", oldrefname);
@@ -1299,10 +1297,10 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
 	if (!symref)
 		return error("refname %s not found", oldrefname);
 
-	if (!is_refname_available(newrefname, oldrefname, get_packed_refs(NULL)))
+	if (!is_refname_available(newrefname, oldrefname, get_packed_refs(refs)))
 		return 1;
 
-	if (!is_refname_available(newrefname, oldrefname, get_loose_refs(NULL)))
+	if (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))
 		return 1;
 
 	lock = lock_ref_sha1_basic(renamed_ref, NULL, 0, NULL);

From 5f5e9a12eef3c20eeefb89e5922008b5900b098b Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:20 +0200
Subject: [PATCH 2220/3720] get_ref_dir(): change signature

Change get_ref_dir() to take a (struct ref_cache *) in place of the
submodule name.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/refs.c b/refs.c
index 9051b9f8c2..01f6c4b52b 100644
--- a/refs.c
+++ b/refs.c
@@ -300,14 +300,14 @@ static struct ref_array *get_packed_refs(struct ref_cache *refs)
 	return &refs->packed;
 }
 
-static void get_ref_dir(const char *submodule, const char *base,
+static void get_ref_dir(struct ref_cache *refs, const char *base,
 			struct ref_array *array)
 {
 	DIR *dir;
 	const char *path;
 
-	if (*submodule)
-		path = git_path_submodule(submodule, "%s", base);
+	if (*refs->name)
+		path = git_path_submodule(refs->name, "%s", base);
 	else
 		path = git_path("%s", base);
 
@@ -338,19 +338,19 @@ static void get_ref_dir(const char *submodule, const char *base,
 			if (has_extension(de->d_name, ".lock"))
 				continue;
 			memcpy(ref + baselen, de->d_name, namelen+1);
-			refdir = submodule
-				? git_path_submodule(submodule, "%s", ref)
+			refdir = *refs->name
+				? git_path_submodule(refs->name, "%s", ref)
 				: git_path("%s", ref);
 			if (stat(refdir, &st) < 0)
 				continue;
 			if (S_ISDIR(st.st_mode)) {
-				get_ref_dir(submodule, ref, array);
+				get_ref_dir(refs, ref, array);
 				continue;
 			}
-			if (submodule) {
+			if (*refs->name) {
 				hashclr(sha1);
 				flag = 0;
-				if (resolve_gitlink_ref(submodule, ref, sha1) < 0) {
+				if (resolve_gitlink_ref(refs->name, ref, sha1) < 0) {
 					hashclr(sha1);
 					flag |= REF_BROKEN;
 				}
@@ -403,7 +403,7 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
 static struct ref_array *get_loose_refs(struct ref_cache *refs)
 {
 	if (!refs->did_loose) {
-		get_ref_dir(refs->name, "refs", &refs->loose);
+		get_ref_dir(refs, "refs", &refs->loose);
 		sort_ref_array(&refs->loose);
 		refs->did_loose = 1;
 	}

From 41e62b55050ebb57d39afd03e2e2833eca2246ef Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:21 +0200
Subject: [PATCH 2221/3720] resolve_gitlink_ref(): improve docstring

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/refs.h b/refs.h
index c6b87495e6..d31e8b171a 100644
--- a/refs.h
+++ b/refs.h
@@ -132,8 +132,12 @@ extern char *shorten_unambiguous_ref(const char *refname, int strict);
 /** rename ref, return 0 on success **/
 extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);
 
-/** resolve ref in nested "gitlink" repository */
-extern int resolve_gitlink_ref(const char *name, const char *refname, unsigned char *sha1);
+/*
+ * Resolve refname in the nested "gitlink" repository that is located
+ * at path.  If the resolution is successful, return 0 and set sha1 to
+ * the name of the object; otherwise, return a non-zero value.
+ */
+extern int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1);
 
 /** lock a ref and then write its file */
 enum action_on_err { MSG_ON_ERR, DIE_ON_ERR, QUIET_ON_ERR };

From 4e4f475b1d89ac0bd7928abd85b63cf4ec554e52 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:22 +0200
Subject: [PATCH 2222/3720] Pass a (ref_cache *) to the resolve_gitlink_*()
 helper functions

And remove some redundant arguments from resolve_gitlink_packed_ref().

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/refs.c b/refs.c
index 01f6c4b52b..984f2f74f6 100644
--- a/refs.c
+++ b/refs.c
@@ -414,12 +414,12 @@ static struct ref_array *get_loose_refs(struct ref_cache *refs)
 #define MAXDEPTH 5
 #define MAXREFLEN (1024)
 
-static int resolve_gitlink_packed_ref(char *name, int pathlen,
+static int resolve_gitlink_packed_ref(struct ref_cache *refs,
 				      const char *refname, unsigned char *sha1)
 {
 	int retval = -1;
 	struct ref_entry *ref;
-	struct ref_array *array = get_packed_refs(get_ref_cache(name));
+	struct ref_array *array = get_packed_refs(refs);
 
 	ref = search_ref_array(array, refname);
 	if (ref != NULL) {
@@ -429,7 +429,8 @@ static int resolve_gitlink_packed_ref(char *name, int pathlen,
 	return retval;
 }
 
-static int resolve_gitlink_ref_recursive(char *name, int pathlen,
+static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
+					 char *name, int pathlen,
 					 const char *refname, unsigned char *sha1,
 					 int recursion)
 {
@@ -441,7 +442,7 @@ static int resolve_gitlink_ref_recursive(char *name, int pathlen,
 	memcpy(name + pathlen, refname, len+1);
 	fd = open(name, O_RDONLY);
 	if (fd < 0)
-		return resolve_gitlink_packed_ref(name, pathlen, refname, sha1);
+		return resolve_gitlink_packed_ref(refs, refname, sha1);
 
 	len = read(fd, buffer, sizeof(buffer)-1);
 	close(fd);
@@ -462,19 +463,24 @@ static int resolve_gitlink_ref_recursive(char *name, int pathlen,
 	while (isspace(*p))
 		p++;
 
-	return resolve_gitlink_ref_recursive(name, pathlen, p, sha1, recursion+1);
+	return resolve_gitlink_ref_recursive(refs, name, pathlen, p, sha1, recursion+1);
 }
 
 int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
 {
 	int len = strlen(path), retval;
-	char *gitdir;
+	char *submodule, *gitdir;
+	struct ref_cache *refs;
 	const char *tmp;
 
 	while (len && path[len-1] == '/')
 		len--;
 	if (!len)
 		return -1;
+	submodule = xstrndup(path, len);
+	refs = get_ref_cache(submodule);
+	free(submodule);
+
 	gitdir = xmalloc(len + MAXREFLEN + 8);
 	memcpy(gitdir, path, len);
 	memcpy(gitdir + len, "/.git", 6);
@@ -489,7 +495,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
 	}
 	gitdir[len] = '/';
 	gitdir[++len] = '\0';
-	retval = resolve_gitlink_ref_recursive(gitdir, len, refname, sha1, 0);
+	retval = resolve_gitlink_ref_recursive(refs, gitdir, len, refname, sha1, 0);
 	free(gitdir);
 	return retval;
 }

From 973592ca53225b2957e548b5b728940d5d5eca99 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Mon, 17 Oct 2011 09:39:23 +0200
Subject: [PATCH 2223/3720] resolve_gitlink_ref_recursive(): change to work
 with struct ref_cache

resolve_gitlink_ref() and resolve_gitlink_ref_recursive(), together,
basically duplicated the code in git_path_submodule().  So use that
function instead.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 34 ++++++++++------------------------
 1 file changed, 10 insertions(+), 24 deletions(-)

diff --git a/refs.c b/refs.c
index 984f2f74f6..7e6cea5458 100644
--- a/refs.c
+++ b/refs.c
@@ -430,17 +430,19 @@ static int resolve_gitlink_packed_ref(struct ref_cache *refs,
 }
 
 static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
-					 char *name, int pathlen,
 					 const char *refname, unsigned char *sha1,
 					 int recursion)
 {
-	int fd, len = strlen(refname);
+	int fd, len;
 	char buffer[128], *p;
+	char *path;
 
-	if (recursion > MAXDEPTH || len > MAXREFLEN)
+	if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
 		return -1;
-	memcpy(name + pathlen, refname, len+1);
-	fd = open(name, O_RDONLY);
+	path = *refs->name
+		? git_path_submodule(refs->name, "%s", refname)
+		: git_path("%s", refname);
+	fd = open(path, O_RDONLY);
 	if (fd < 0)
 		return resolve_gitlink_packed_ref(refs, refname, sha1);
 
@@ -463,15 +465,14 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
 	while (isspace(*p))
 		p++;
 
-	return resolve_gitlink_ref_recursive(refs, name, pathlen, p, sha1, recursion+1);
+	return resolve_gitlink_ref_recursive(refs, p, sha1, recursion+1);
 }
 
 int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
 {
 	int len = strlen(path), retval;
-	char *submodule, *gitdir;
+	char *submodule;
 	struct ref_cache *refs;
-	const char *tmp;
 
 	while (len && path[len-1] == '/')
 		len--;
@@ -481,22 +482,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
 	refs = get_ref_cache(submodule);
 	free(submodule);
 
-	gitdir = xmalloc(len + MAXREFLEN + 8);
-	memcpy(gitdir, path, len);
-	memcpy(gitdir + len, "/.git", 6);
-	len += 5;
-
-	tmp = read_gitfile(gitdir);
-	if (tmp) {
-		free(gitdir);
-		len = strlen(tmp);
-		gitdir = xmalloc(len + MAXREFLEN + 3);
-		memcpy(gitdir, tmp, len);
-	}
-	gitdir[len] = '/';
-	gitdir[++len] = '\0';
-	retval = resolve_gitlink_ref_recursive(refs, gitdir, len, refname, sha1, 0);
-	free(gitdir);
+	retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
 	return retval;
 }
 

From 7b316a49b55a2cbe0321e72dce28a92126801d49 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Tue, 18 Oct 2011 18:20:35 +0200
Subject: [PATCH 2224/3720] inet_ntop.c: Work around GCC 4.6's detection of
 uninitialized variables

GCC 4.6 claims that

    error: 'best.len' may be used uninitialized in this function

so silence that warning which is treated as an error by also initializing
the "len" members of the struct.

Signed-off-by: Sebastian Schuberth 
---
 compat/inet_ntop.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/inet_ntop.c b/compat/inet_ntop.c
index ea249c6ac6..9e9f6fbbbc 100644
--- a/compat/inet_ntop.c
+++ b/compat/inet_ntop.c
@@ -98,7 +98,8 @@ inet_ntop6(const u_char *src, char *dst, size_t size)
 	for (i = 0; i < NS_IN6ADDRSZ; i++)
 		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
 	best.base = -1;
-	cur.base = -1;
+	best.len = 0;
+	cur = best;
 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
 		if (words[i] == 0) {
 			if (cur.base == -1)

From a56e777983874da0937cf2ba5d8bfb26c9956169 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Wed, 19 Oct 2011 13:41:18 -0700
Subject: [PATCH 2225/3720] Revert "Restrict ref-like names immediately below
 $GIT_DIR"

This reverts commit 2f6af3820eb61f30cf102b345d35028047300b74; we shouldn't
be changing the traditional behaviour without devising a proper transtion
plan only to hastily fix fallouts on the master branch.
---
 refs.c | 35 ++---------------------------------
 1 file changed, 2 insertions(+), 33 deletions(-)

diff --git a/refs.c b/refs.c
index 2eb9c04443..e3692bd3d8 100644
--- a/refs.c
+++ b/refs.c
@@ -994,33 +994,12 @@ const char *ref_fetch_rules[] = {
 	NULL
 };
 
-static int refname_ok_at_root_level(const char *str, int len)
-{
-	if (len >= 5 && !memcmp(str, "refs/", 5))
-		return 1;
-
-	while (len--) {
-		char ch = *str++;
-
-		/*
-		 * Only accept likes of .git/HEAD, .git/MERGE_HEAD at
-		 * the root level as a ref.
-		 */
-		if (ch != '_' && (ch < 'A' || 'Z' < ch))
-			return 0;
-	}
-	return 1;
-}
-
 int refname_match(const char *abbrev_name, const char *full_name, const char **rules)
 {
 	const char **p;
 	const int abbrev_name_len = strlen(abbrev_name);
 
 	for (p = rules; *p; p++) {
-		if (p == rules &&
-		    !refname_ok_at_root_level(abbrev_name, abbrev_name_len))
-			continue;
 		if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {
 			return 1;
 		}
@@ -1121,8 +1100,6 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
 		unsigned char *this_result;
 		int flag;
 
-		if (p == ref_rev_parse_rules && !refname_ok_at_root_level(str, len))
-			continue;
 		this_result = refs_found ? sha1_from_ref : sha1;
 		mksnpath(fullref, sizeof(fullref), *p, len, str);
 		r = resolve_ref(fullref, this_result, 1, &flag);
@@ -1151,8 +1128,6 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
 		char path[PATH_MAX];
 		const char *ref, *it;
 
-		if (p == ref_rev_parse_rules && !refname_ok_at_root_level(str, len))
-			continue;
 		mksnpath(path, sizeof(path), *p, len, str);
 		ref = resolve_ref(path, hash, 1, NULL);
 		if (!ref)
@@ -2070,14 +2045,12 @@ char *shorten_unambiguous_ref(const char *ref, int strict)
 	/* buffer for scanf result, at most ref must fit */
 	short_name = xstrdup(ref);
 
-	for (i = nr_rules - 1; i >= 0; i--) {
+	/* skip first rule, it will always match */
+	for (i = nr_rules - 1; i > 0 ; --i) {
 		int j;
 		int rules_to_fail = i;
 		int short_name_len;
 
-		if (!i && !refname_ok_at_root_level(ref, strlen(ref)))
-			continue;
-
 		if (1 != sscanf(ref, scanf_fmts[i], short_name))
 			continue;
 
@@ -2103,10 +2076,6 @@ char *shorten_unambiguous_ref(const char *ref, int strict)
 			if (i == j)
 				continue;
 
-			if (!j &&
-			    !refname_ok_at_root_level(short_name, short_name_len))
-				continue;
-
 			/*
 			 * the short name is ambiguous, if it resolves
 			 * (with this previous rule) to a valid ref

From 89587fadb211e9c07c3bb2f05f0e90b3a57ac340 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Wed, 7 Sep 2011 21:19:47 -0700
Subject: [PATCH 2226/3720] Split GPG interface into its own helper library

This mostly moves existing code from builtin/tag.c (for signing)
and builtin/verify-tag.c (for verifying) to a new gpg-interface.c
file to provide a more generic library interface.

 - sign_buffer() takes a payload strbuf, a signature strbuf, and a signing
   key, runs "gpg" to produce a detached signature for the payload, and
   appends it to the signature strbuf. The contents of a signed tag that
   concatenates the payload and the detached signature can be produced by
   giving the same strbuf as payload and signature strbuf.

 - verify_signed_buffer() takes a payload and a detached signature as
    pairs, and runs "gpg --verify" to see if the payload matches
   the signature. It can optionally capture the output from GPG to allow
   the callers to pretty-print it in a way more suitable for their
   contexts.

"verify-tag" (aka "tag -v") used to save the whole tag contents as if it
is a detached signature, and fed gpg the payload part of the tag. It
relied on gpg to fail when the given tag is not signed but just is
annotated.  The updated run_gpg_verify() function detects the lack of
detached signature in the input, and errors out without bothering "gpg".

Signed-off-by: Junio C Hamano 
---
 Makefile             |   2 +
 builtin/tag.c        |  76 ++----------------------
 builtin/verify-tag.c |  35 ++---------
 gpg-interface.c      | 138 +++++++++++++++++++++++++++++++++++++++++++
 gpg-interface.h      |  10 ++++
 tag.c                |   5 ++
 6 files changed, 166 insertions(+), 100 deletions(-)
 create mode 100644 gpg-interface.c
 create mode 100644 gpg-interface.h

diff --git a/Makefile b/Makefile
index 8d6d4515d2..2183223759 100644
--- a/Makefile
+++ b/Makefile
@@ -530,6 +530,7 @@ LIB_H += exec_cmd.h
 LIB_H += fsck.h
 LIB_H += gettext.h
 LIB_H += git-compat-util.h
+LIB_H += gpg-interface.h
 LIB_H += graph.h
 LIB_H += grep.h
 LIB_H += hash.h
@@ -620,6 +621,7 @@ LIB_OBJS += entry.o
 LIB_OBJS += environment.o
 LIB_OBJS += exec_cmd.o
 LIB_OBJS += fsck.o
+LIB_OBJS += gpg-interface.o
 LIB_OBJS += graph.o
 LIB_OBJS += grep.o
 LIB_OBJS += hash.o
diff --git a/builtin/tag.c b/builtin/tag.c
index 667515e527..fb0d4a1648 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -14,6 +14,7 @@
 #include "parse-options.h"
 #include "diff.h"
 #include "revision.h"
+#include "gpg-interface.h"
 
 static const char * const git_tag_usage[] = {
 	"git tag [-a|-s|-u ] [-f] [-m |-F ]  []",
@@ -23,8 +24,6 @@ static const char * const git_tag_usage[] = {
 	NULL
 };
 
-static char signingkey[1000];
-
 struct tag_filter {
 	const char **patterns;
 	int lines;
@@ -208,60 +207,7 @@ static int verify_tag(const char *name, const char *ref,
 
 static int do_sign(struct strbuf *buffer)
 {
-	struct child_process gpg;
-	const char *args[4];
-	char *bracket;
-	int len;
-	int i, j;
-
-	if (!*signingkey) {
-		if (strlcpy(signingkey, git_committer_info(IDENT_ERROR_ON_NO_NAME),
-				sizeof(signingkey)) > sizeof(signingkey) - 1)
-			return error(_("committer info too long."));
-		bracket = strchr(signingkey, '>');
-		if (bracket)
-			bracket[1] = '\0';
-	}
-
-	/* When the username signingkey is bad, program could be terminated
-	 * because gpg exits without reading and then write gets SIGPIPE. */
-	signal(SIGPIPE, SIG_IGN);
-
-	memset(&gpg, 0, sizeof(gpg));
-	gpg.argv = args;
-	gpg.in = -1;
-	gpg.out = -1;
-	args[0] = "gpg";
-	args[1] = "-bsau";
-	args[2] = signingkey;
-	args[3] = NULL;
-
-	if (start_command(&gpg))
-		return error(_("could not run gpg."));
-
-	if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
-		close(gpg.in);
-		close(gpg.out);
-		finish_command(&gpg);
-		return error(_("gpg did not accept the tag data"));
-	}
-	close(gpg.in);
-	len = strbuf_read(buffer, gpg.out, 1024);
-	close(gpg.out);
-
-	if (finish_command(&gpg) || !len || len < 0)
-		return error(_("gpg failed to sign the tag"));
-
-	/* Strip CR from the line endings, in case we are on Windows. */
-	for (i = j = 0; i < buffer->len; i++)
-		if (buffer->buf[i] != '\r') {
-			if (i != j)
-				buffer->buf[j] = buffer->buf[i];
-			j++;
-		}
-	strbuf_setlen(buffer, j);
-
-	return 0;
+	return sign_buffer(buffer, buffer, get_signing_key());
 }
 
 static const char tag_template[] =
@@ -270,21 +216,11 @@ static const char tag_template[] =
 	"# Write a tag message\n"
 	"#\n");
 
-static void set_signingkey(const char *value)
-{
-	if (strlcpy(signingkey, value, sizeof(signingkey)) >= sizeof(signingkey))
-		die(_("signing key value too long (%.10s...)"), value);
-}
-
 static int git_tag_config(const char *var, const char *value, void *cb)
 {
-	if (!strcmp(var, "user.signingkey")) {
-		if (!value)
-			return config_error_nonbool(var);
-		set_signingkey(value);
-		return 0;
-	}
-
+	int status = git_gpg_config(var, value, cb);
+	if (status)
+		return status;
 	return git_default_config(var, value, cb);
 }
 
@@ -463,7 +399,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
 	if (keyid) {
 		sign = 1;
-		set_signingkey(keyid);
+		set_signing_key(keyid);
 	}
 	if (sign)
 		annotate = 1;
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 3134766049..28c2174338 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -11,6 +11,7 @@
 #include "run-command.h"
 #include 
 #include "parse-options.h"
+#include "gpg-interface.h"
 
 static const char * const verify_tag_usage[] = {
 		"git verify-tag [-v|--verbose] ...",
@@ -19,42 +20,16 @@ static const char * const verify_tag_usage[] = {
 
 static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
 {
-	struct child_process gpg;
-	const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
-	char path[PATH_MAX];
-	size_t len;
-	int fd, ret;
+	int len;
 
-	fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
-	if (fd < 0)
-		return error("could not create temporary file '%s': %s",
-						path, strerror(errno));
-	if (write_in_full(fd, buf, size) < 0)
-		return error("failed writing temporary file '%s': %s",
-						path, strerror(errno));
-	close(fd);
-
-	/* find the length without signature */
 	len = parse_signature(buf, size);
 	if (verbose)
 		write_in_full(1, buf, len);
 
-	memset(&gpg, 0, sizeof(gpg));
-	gpg.argv = args_gpg;
-	gpg.in = -1;
-	args_gpg[2] = path;
-	if (start_command(&gpg)) {
-		unlink(path);
-		return error("could not run gpg.");
-	}
+	if (size == len)
+		return error("no signature found");
 
-	write_in_full(gpg.in, buf, len);
-	close(gpg.in);
-	ret = finish_command(&gpg);
-
-	unlink_or_warn(path);
-
-	return ret;
+	return verify_signed_buffer(buf, len, buf + len, size - len, NULL);
 }
 
 static int verify_tag(const char *name, int verbose)
diff --git a/gpg-interface.c b/gpg-interface.c
new file mode 100644
index 0000000000..ff232c8c5d
--- /dev/null
+++ b/gpg-interface.c
@@ -0,0 +1,138 @@
+#include "cache.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "gpg-interface.h"
+#include "sigchain.h"
+
+static char *configured_signing_key;
+
+void set_signing_key(const char *key)
+{
+	free(configured_signing_key);
+	configured_signing_key = xstrdup(key);
+}
+
+int git_gpg_config(const char *var, const char *value, void *cb)
+{
+	if (!strcmp(var, "user.signingkey")) {
+		if (!value)
+			return config_error_nonbool(var);
+		set_signing_key(value);
+	}
+	return 0;
+}
+
+const char *get_signing_key(void)
+{
+	if (configured_signing_key)
+		return configured_signing_key;
+	return git_committer_info(IDENT_ERROR_ON_NO_NAME|IDENT_NO_DATE);
+}
+
+/*
+ * Create a detached signature for the contents of "buffer" and append
+ * it after "signature"; "buffer" and "signature" can be the same
+ * strbuf instance, which would cause the detached signature appended
+ * at the end.
+ */
+int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
+{
+	struct child_process gpg;
+	const char *args[4];
+	ssize_t len;
+	size_t i, j, bottom;
+
+	memset(&gpg, 0, sizeof(gpg));
+	gpg.argv = args;
+	gpg.in = -1;
+	gpg.out = -1;
+	args[0] = "gpg";
+	args[1] = "-bsau";
+	args[2] = signing_key;
+	args[3] = NULL;
+
+	if (start_command(&gpg))
+		return error(_("could not run gpg."));
+
+	/*
+	 * When the username signingkey is bad, program could be terminated
+	 * because gpg exits without reading and then write gets SIGPIPE.
+	 */
+	sigchain_push(SIGPIPE, SIG_IGN);
+
+	if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
+		close(gpg.in);
+		close(gpg.out);
+		finish_command(&gpg);
+		return error(_("gpg did not accept the data"));
+	}
+	close(gpg.in);
+
+	bottom = signature->len;
+	len = strbuf_read(signature, gpg.out, 1024);
+	close(gpg.out);
+
+	sigchain_pop(SIGPIPE);
+
+	if (finish_command(&gpg) || !len || len < 0)
+		return error(_("gpg failed to sign the data"));
+
+	/* Strip CR from the line endings, in case we are on Windows. */
+	for (i = j = bottom; i < signature->len; i++)
+		if (signature->buf[i] != '\r') {
+			if (i != j)
+				signature->buf[j] = signature->buf[i];
+			j++;
+		}
+	strbuf_setlen(signature, j);
+
+	return 0;
+}
+
+/*
+ * Run "gpg" to see if the payload matches the detached signature.
+ * gpg_output_to tells where the output from "gpg" should go:
+ *   < 0: /dev/null
+ *   = 0: standard error of the calling process
+ *   > 0: the specified file descriptor
+ */
+int verify_signed_buffer(const char *payload, size_t payload_size,
+			 const char *signature, size_t signature_size,
+			 struct strbuf *gpg_output)
+{
+	struct child_process gpg;
+	const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
+	char path[PATH_MAX];
+	int fd, ret;
+
+	fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
+	if (fd < 0)
+		return error("could not create temporary file '%s': %s",
+			     path, strerror(errno));
+	if (write_in_full(fd, signature, signature_size) < 0)
+		return error("failed writing detached signature to '%s': %s",
+			     path, strerror(errno));
+	close(fd);
+
+	memset(&gpg, 0, sizeof(gpg));
+	gpg.argv = args_gpg;
+	gpg.in = -1;
+	if (gpg_output)
+		gpg.err = -1;
+	args_gpg[2] = path;
+	if (start_command(&gpg)) {
+		unlink(path);
+		return error("could not run gpg.");
+	}
+
+	write_in_full(gpg.in, payload, payload_size);
+	close(gpg.in);
+
+	if (gpg_output)
+		strbuf_read(gpg_output, gpg.err, 0);
+	ret = finish_command(&gpg);
+
+	unlink_or_warn(path);
+
+	return ret;
+}
diff --git a/gpg-interface.h b/gpg-interface.h
new file mode 100644
index 0000000000..b9c36088ce
--- /dev/null
+++ b/gpg-interface.h
@@ -0,0 +1,10 @@
+#ifndef GPG_INTERFACE_H
+#define GPG_INTERFACE_H
+
+extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key);
+extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output);
+extern int git_gpg_config(const char *, const char *, void *);
+extern void set_signing_key(const char *);
+extern const char *get_signing_key(void);
+
+#endif
diff --git a/tag.c b/tag.c
index 7d38cc0f4d..3aa186df62 100644
--- a/tag.c
+++ b/tag.c
@@ -139,6 +139,11 @@ int parse_tag(struct tag *item)
 	return ret;
 }
 
+/*
+ * Look at a signed tag object, and return the offset where
+ * the embedded detached signature begins, or the end of the
+ * data when there is no such signature.
+ */
 size_t parse_signature(const char *buf, unsigned long size)
 {
 	char *eol;

From 49b5f81713ef23f37a46e847d69327ad5765cd51 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Wed, 5 Oct 2011 17:23:20 -0700
Subject: [PATCH 2227/3720] commit: teach --gpg-sign option

And this uses the gpg-interface.[ch] to allow signing the commit, i.e.

    $ git commit --gpg-sign -m foo
    You need a passphrase to unlock the secret key for
    user: "Junio C Hamano "
    4096-bit RSA key, ID 96AFE6CB, created 2011-10-03 (main key ID 713660A7)

    [master 8457d13] foo
     1 files changed, 1 insertions(+), 0 deletions(-)

The lines of GPG detached signature are placed in new header lines, after
the standard tree/parent/author/committer headers, instead of tucking the
signature block at the end of the commit log message text (similar to how
signed tag is done), for multiple reasons:

 - The signature won't clutter output from "git log" and friends if it is
   in the extra header. If we place it at the end of the log message, we
   would need to teach "git log" and friends to strip the signature block
   with an option.

 - Teaching new versions of "git log" and "gitk" to optionally verify and
   show signatures is cleaner if we structurally know where the signature
   block is (instead of scanning in the commit log message).

 - The signature needs to be stripped upon various commit rewriting
   operations, e.g. rebase, filter-branch, etc. They all already ignore
   unknown headers, but if we place signature in the log message, all of
   these tools (and third-party tools) also need to learn how a signature
   block would look like.

 - When we added the optional encoding header, all the tools (both in tree
   and third-party) that acts on the raw commit object should have been
   fixed to ignore headers they do not understand, so it is not like that
   new header would be more likely to break than extra text in the commit.

A commit made with the above sample sequence would look like this:

    $ git cat-file commit HEAD
    tree 3cd71d90e3db4136e5260ab54599791c4f883b9d
    parent b87755351a47b09cb27d6913e6e0e17e6254a4d4
    author Junio C Hamano  1317862251 -0700
    committer Junio C Hamano  1317862251 -0700
    gpgsig -----BEGIN PGP SIGNATURE-----
    gpgsig Version: GnuPG v1.4.10 (GNU/Linux)
    gpgsig
    gpgsig iQIcBAABAgAGBQJOjPtrAAoJELC16IaWr+bL4TMP/RSe2Y/jYnCkds9unO5JEnfG
    gpgsig ...
    gpgsig =dt98
    gpgsig -----END PGP SIGNATURE-----

    foo

but "git log" (unless you ask for it with --pretty=raw) output is not
cluttered with the signature information.

Signed-off-by: Junio C Hamano 
---
 builtin/commit-tree.c | 24 +++++++++++++++++++++---
 builtin/commit.c      | 12 ++++++++++--
 builtin/merge.c       | 16 ++++++++++++++--
 commit.c              | 40 +++++++++++++++++++++++++++++++++++++++-
 commit.h              |  2 +-
 notes-cache.c         |  2 +-
 notes-merge.c         |  2 +-
 7 files changed, 87 insertions(+), 11 deletions(-)

diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index d083795e26..a17811f958 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -8,8 +8,9 @@
 #include "tree.h"
 #include "builtin.h"
 #include "utf8.h"
+#include "gpg-interface.h"
 
-static const char commit_tree_usage[] = "git commit-tree  [(-p )...] < changelog";
+static const char commit_tree_usage[] = "git commit-tree [-S]  [(-p )...] < changelog";
 
 static void new_parent(struct commit *parent, struct commit_list **parents_p)
 {
@@ -25,6 +26,14 @@ static void new_parent(struct commit *parent, struct commit_list **parents_p)
 	commit_list_insert(parent, parents_p);
 }
 
+static int commit_tree_config(const char *var, const char *value, void *cb)
+{
+	int status = git_gpg_config(var, value, NULL);
+	if (status)
+		return status;
+	return git_default_config(var, value, cb);
+}
+
 int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 {
 	int i;
@@ -32,11 +41,19 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 	unsigned char tree_sha1[20];
 	unsigned char commit_sha1[20];
 	struct strbuf buffer = STRBUF_INIT;
+	const char *sign_commit = NULL;
 
-	git_config(git_default_config, NULL);
+	git_config(commit_tree_config, NULL);
 
 	if (argc < 2 || !strcmp(argv[1], "-h"))
 		usage(commit_tree_usage);
+
+	if (!memcmp(argv[1], "-S", 2)) {
+		sign_commit = argv[1] + 2;
+		argv++;
+		argc--;
+	}
+
 	if (get_sha1(argv[1], tree_sha1))
 		die("Not a valid object name %s", argv[1]);
 
@@ -56,7 +73,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 	if (strbuf_read(&buffer, 0, 0) < 0)
 		die_errno("git commit-tree: failed to read");
 
-	if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
+	if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1,
+			NULL, sign_commit)) {
 		strbuf_release(&buffer);
 		return 1;
 	}
diff --git a/builtin/commit.c b/builtin/commit.c
index cbc9613ec6..90cf7e812b 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -26,6 +26,7 @@
 #include "unpack-trees.h"
 #include "quote.h"
 #include "submodule.h"
+#include "gpg-interface.h"
 
 static const char * const builtin_commit_usage[] = {
 	"git commit [options] [--] ...",
@@ -85,6 +86,8 @@ static int all, edit_flag, also, interactive, patch_interactive, only, amend, si
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int no_post_rewrite, allow_empty_message;
 static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
+static char *sign_commit;
+
 /*
  * The default commit message cleanup mode will remove the lines
  * beginning with # (shell comments) and leading and trailing
@@ -144,6 +147,8 @@ static struct option builtin_commit_options[] = {
 	OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
 	OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
 	OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
+	{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
+	  "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
 	/* end commit message options */
 
 	OPT_GROUP("Commit contents options"),
@@ -1323,6 +1328,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
 static int git_commit_config(const char *k, const char *v, void *cb)
 {
 	struct wt_status *s = cb;
+	int status;
 
 	if (!strcmp(k, "commit.template"))
 		return git_config_pathname(&template_file, k, v);
@@ -1330,7 +1336,9 @@ static int git_commit_config(const char *k, const char *v, void *cb)
 		include_status = git_config_bool(k, v);
 		return 0;
 	}
-
+	status = git_gpg_config(k, v, NULL);
+	if (status)
+		return status;
 	return git_status_config(k, v, s);
 }
 
@@ -1481,7 +1489,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 	}
 
 	if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1,
-			author_ident.buf)) {
+			author_ident.buf, sign_commit)) {
 		rollback_index_files();
 		die(_("failed to write commit object"));
 	}
diff --git a/builtin/merge.c b/builtin/merge.c
index ab4077f272..53cff0266c 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -26,6 +26,7 @@
 #include "merge-recursive.h"
 #include "resolve-undo.h"
 #include "remote.h"
+#include "gpg-interface.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -63,6 +64,7 @@ static int allow_rerere_auto;
 static int abort_current_merge;
 static int show_progress = -1;
 static int default_to_upstream;
+static const char *sign_commit;
 
 static struct strategy all_strategy[] = {
 	{ "recursive",  DEFAULT_TWOHEAD | NO_TRIVIAL },
@@ -206,6 +208,8 @@ static struct option builtin_merge_options[] = {
 	OPT_BOOLEAN(0, "abort", &abort_current_merge,
 		"abort the current in-progress merge"),
 	OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
+	{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
+	  "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
 	OPT_END()
 };
 
@@ -525,6 +529,8 @@ static void parse_branch_merge_options(char *bmo)
 
 static int git_merge_config(const char *k, const char *v, void *cb)
 {
+	int status;
+
 	if (branch && !prefixcmp(k, "branch.") &&
 		!prefixcmp(k + 7, branch) &&
 		!strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
@@ -562,6 +568,10 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		default_to_upstream = git_config_bool(k, v);
 		return 0;
 	}
+
+	status = git_gpg_config(k, v, NULL);
+	if (status)
+		return status;
 	return git_diff_ui_config(k, v, cb);
 }
 
@@ -870,7 +880,8 @@ static int merge_trivial(void)
 	parent->next->item = remoteheads->item;
 	parent->next->next = NULL;
 	run_prepare_commit_msg();
-	commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
+	commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL,
+		    sign_commit);
 	finish(result_commit, "In-index merge");
 	drop_save();
 	return 0;
@@ -900,7 +911,8 @@ static int finish_automerge(struct commit_list *common,
 	free_commit_list(remoteheads);
 	strbuf_addch(&merge_msg, '\n');
 	run_prepare_commit_msg();
-	commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
+	commit_tree(merge_msg.buf, result_tree, parents, result_commit,
+		    NULL, sign_commit);
 	strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
 	finish(result_commit, buf.buf);
 	strbuf_release(&buf);
diff --git a/commit.c b/commit.c
index 97b43279cd..4bff3cdaae 100644
--- a/commit.c
+++ b/commit.c
@@ -6,6 +6,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "notes.h"
+#include "gpg-interface.h"
 
 int save_commit_buffer = 1;
 
@@ -814,6 +815,40 @@ struct commit_list *reduce_heads(struct commit_list *heads)
 	return result;
 }
 
+static const char gpg_sig_header[] = "gpgsig ";
+static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;
+
+static int do_sign_commit(struct strbuf *buf, const char *keyid)
+{
+	struct strbuf sig = STRBUF_INIT;
+	int inspos, copypos;
+
+	/* find the end of the header */
+	inspos = strstr(buf->buf, "\n\n") - buf->buf + 1;
+
+	if (!keyid || !*keyid)
+		keyid = get_signing_key();
+	if (sign_buffer(buf, &sig, keyid)) {
+		strbuf_release(&sig);
+		return -1;
+	}
+
+	for (copypos = 0; sig.buf[copypos]; ) {
+		const char *bol = sig.buf + copypos;
+		const char *eol = strchrnul(bol, '\n');
+		int len = (eol - bol) + !!*eol;
+
+		strbuf_insert(buf, inspos, gpg_sig_header, gpg_sig_header_len);
+		inspos += gpg_sig_header_len;
+		strbuf_insert(buf, inspos, bol, len);
+		inspos += len;
+		copypos += len;
+	}
+	strbuf_release(&sig);
+	return 0;
+}
+
+
 static const char commit_utf8_warn[] =
 "Warning: commit message does not conform to UTF-8.\n"
 "You may want to amend it after fixing the message, or set the config\n"
@@ -821,7 +856,7 @@ static const char commit_utf8_warn[] =
 
 int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret,
-		const char *author)
+		const char *author, const char *sign_commit)
 {
 	int result;
 	int encoding_is_utf8;
@@ -864,6 +899,9 @@ int commit_tree(const char *msg, unsigned char *tree,
 	if (encoding_is_utf8 && !is_utf8(buffer.buf))
 		fprintf(stderr, commit_utf8_warn);
 
+	if (sign_commit && do_sign_commit(&buffer, sign_commit))
+		return -1;
+
 	result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
 	strbuf_release(&buffer);
 	return result;
diff --git a/commit.h b/commit.h
index 12d100b8b6..8c2419b51f 100644
--- a/commit.h
+++ b/commit.h
@@ -175,6 +175,6 @@ struct commit_list *reduce_heads(struct commit_list *heads);
 
 extern int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret,
-		const char *author);
+		       const char *author, const char *sign_commit);
 
 #endif /* COMMIT_H */
diff --git a/notes-cache.c b/notes-cache.c
index 4c8984ede1..c36a960bc3 100644
--- a/notes-cache.c
+++ b/notes-cache.c
@@ -56,7 +56,7 @@ int notes_cache_write(struct notes_cache *c)
 
 	if (write_notes_tree(&c->tree, tree_sha1))
 		return -1;
-	if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL) < 0)
+	if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL, NULL) < 0)
 		return -1;
 	if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
 		       0, QUIET_ON_ERR) < 0)
diff --git a/notes-merge.c b/notes-merge.c
index e1aaf43b43..c29c434156 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -546,7 +546,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
 		/* else: t->ref points to nothing, assume root/orphan commit */
 	}
 
-	if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL))
+	if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL))
 		die("Failed to commit notes tree to database");
 }
 

From 93104a2742d01adf97f173bda63c12382c77aae2 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Tue, 18 Oct 2011 15:53:23 -0700
Subject: [PATCH 2228/3720] log: --show-signature

This teaches the "log" family of commands to pass the GPG signature in the
commit objects to "gpg --verify" via the verify_signed_buffer() interface
used to verify signed tag objects. E.g.

    $ git show --show-signature -s HEAD

shows GPG output in the header part of the output.

Signed-off-by: Junio C Hamano 
---
 commit.c   | 34 ++++++++++++++++++++++++++++++++++
 commit.h   |  3 +++
 log-tree.c | 39 +++++++++++++++++++++++++++++++++++++++
 revision.c |  2 ++
 revision.h |  1 +
 5 files changed, 79 insertions(+)

diff --git a/commit.c b/commit.c
index 4bff3cdaae..93045a2cda 100644
--- a/commit.c
+++ b/commit.c
@@ -848,6 +848,40 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
 	return 0;
 }
 
+int parse_signed_commit(const unsigned char *sha1,
+			struct strbuf *payload, struct strbuf *signature)
+{
+	unsigned long size;
+	enum object_type type;
+	char *buffer = read_sha1_file(sha1, &type, &size);
+	int in_header, saw_signature = -1;
+	char *line;
+
+	if (!buffer || type != OBJ_COMMIT)
+		goto cleanup;
+
+	line = buffer;
+	in_header = 1;
+	saw_signature = 0;
+	while (*line) {
+		char *next = strchrnul(line, '\n');
+		if (*next)
+			next++;
+		if (in_header && !prefixcmp(line, gpg_sig_header)) {
+			const char *sig = line + gpg_sig_header_len;
+			strbuf_add(signature, sig, next - sig);
+			saw_signature = 1;
+		} else {
+			strbuf_add(payload, line, next - line);
+		}
+		if (*line == '\n')
+			in_header = 0;
+		line = next;
+	}
+ cleanup:
+	free(buffer);
+	return saw_signature;
+}
 
 static const char commit_utf8_warn[] =
 "Warning: commit message does not conform to UTF-8.\n"
diff --git a/commit.h b/commit.h
index 8c2419b51f..1885471b8b 100644
--- a/commit.h
+++ b/commit.h
@@ -177,4 +177,7 @@ extern int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret,
 		       const char *author, const char *sign_commit);
 
+extern int parse_signed_commit(const unsigned char *sha1,
+			       struct strbuf *message, struct strbuf *signature);
+
 #endif /* COMMIT_H */
diff --git a/log-tree.c b/log-tree.c
index 24c295ea1d..f7b6976d9f 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -8,6 +8,7 @@
 #include "refs.h"
 #include "string-list.h"
 #include "color.h"
+#include "gpg-interface.h"
 
 struct decoration name_decoration = { "object names" };
 
@@ -395,6 +396,41 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 	*extra_headers_p = extra_headers;
 }
 
+static void show_signature(struct rev_info *opt, struct commit *commit)
+{
+	struct strbuf payload = STRBUF_INIT;
+	struct strbuf signature = STRBUF_INIT;
+	struct strbuf gpg_output = STRBUF_INIT;
+	int status;
+	const char *color, *reset, *bol, *eol;
+
+	if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0)
+		goto out;
+
+	status = verify_signed_buffer(payload.buf, payload.len,
+				      signature.buf, signature.len,
+				      &gpg_output);
+	if (status && !gpg_output.len)
+		strbuf_addstr(&gpg_output, "No signature\n");
+
+	color = diff_get_color_opt(&opt->diffopt,
+				   status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
+	reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
+
+	bol = gpg_output.buf;
+	while (*bol) {
+		eol = strchrnul(bol, '\n');
+		printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
+		       *eol ? "\n" : "");
+		bol = (*eol) ? (eol + 1) : eol;
+	}
+
+ out:
+	strbuf_release(&gpg_output);
+	strbuf_release(&payload);
+	strbuf_release(&signature);
+}
+
 void show_log(struct rev_info *opt)
 {
 	struct strbuf msgbuf = STRBUF_INIT;
@@ -502,6 +538,9 @@ void show_log(struct rev_info *opt)
 		}
 	}
 
+	if (opt->show_signature)
+		show_signature(opt, commit);
+
 	if (!commit->buffer)
 		return;
 
diff --git a/revision.c b/revision.c
index c46cfaa3e4..860a3128a3 100644
--- a/revision.c
+++ b/revision.c
@@ -1381,6 +1381,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->show_notes = 1;
 		revs->show_notes_given = 1;
 		revs->notes_opt.use_default_notes = 1;
+	} else if (!strcmp(arg, "--show-signature")) {
+		revs->show_signature = 1;
 	} else if (!prefixcmp(arg, "--show-notes=") ||
 		   !prefixcmp(arg, "--notes=")) {
 		struct strbuf buf = STRBUF_INIT;
diff --git a/revision.h b/revision.h
index 3d64adad18..198bb95894 100644
--- a/revision.h
+++ b/revision.h
@@ -89,6 +89,7 @@ struct rev_info {
 			show_merge:1,
 			show_notes:1,
 			show_notes_given:1,
+			show_signature:1,
 			pretty_given:1,
 			abbrev_commit:1,
 			abbrev_commit_given:1,

From 009012833cea5a2e4b78529d1012e900664ccd0a Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Wed, 19 Oct 2011 16:45:05 -0700
Subject: [PATCH 2229/3720] t7004: extract generic "GPG testing" bits

Signed-off-by: Junio C Hamano 
---
 t/lib-gpg.sh                     |  29 +++++++++++++++++++++++++++++
 t/{t7004 => lib-gpg}/pubring.gpg | Bin
 t/{t7004 => lib-gpg}/random_seed | Bin
 t/{t7004 => lib-gpg}/secring.gpg | Bin
 t/{t7004 => lib-gpg}/trustdb.gpg | Bin
 t/t7004-tag.sh                   |  29 +----------------------------
 6 files changed, 30 insertions(+), 28 deletions(-)
 create mode 100644 t/lib-gpg.sh
 rename t/{t7004 => lib-gpg}/pubring.gpg (100%)
 rename t/{t7004 => lib-gpg}/random_seed (100%)
 rename t/{t7004 => lib-gpg}/secring.gpg (100%)
 rename t/{t7004 => lib-gpg}/trustdb.gpg (100%)

diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
new file mode 100644
index 0000000000..eb09027175
--- /dev/null
+++ b/t/lib-gpg.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# Check if gpg is available
+gpg --version >/dev/null 2>/dev/null
+if [ $? -eq 127 ]; then
+	say "# gpg not found - skipping tag signing and verification tests"
+else
+	# As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
+	# the gpg version 1.0.6 didn't parse trust packets correctly, so for
+	# that version, creation of signed tags using the generated key fails.
+	case "$(gpg --version)" in
+	'gpg (GnuPG) 1.0.6'*)
+		say "Skipping signed tag tests, because a bug in 1.0.6 version"
+		;;
+	*)
+		test_set_prereq GPG
+		;;
+	esac
+fi
+
+# key generation info: gpg --homedir t/t7004 --gen-key
+# Type DSA and Elgamal, size 2048 bits, no expiration date.
+# Name and email: C O Mitter 
+# No password given, to enable non-interactive operation.
+
+cp -R "$TEST_DIRECTORY"/lib-gpg ./gpghome
+chmod 0700 gpghome
+GNUPGHOME="$(pwd)/gpghome"
+export GNUPGHOME
diff --git a/t/t7004/pubring.gpg b/t/lib-gpg/pubring.gpg
similarity index 100%
rename from t/t7004/pubring.gpg
rename to t/lib-gpg/pubring.gpg
diff --git a/t/t7004/random_seed b/t/lib-gpg/random_seed
similarity index 100%
rename from t/t7004/random_seed
rename to t/lib-gpg/random_seed
diff --git a/t/t7004/secring.gpg b/t/lib-gpg/secring.gpg
similarity index 100%
rename from t/t7004/secring.gpg
rename to t/lib-gpg/secring.gpg
diff --git a/t/t7004/trustdb.gpg b/t/lib-gpg/trustdb.gpg
similarity index 100%
rename from t/t7004/trustdb.gpg
rename to t/lib-gpg/trustdb.gpg
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 097ce2bc83..ded5c86c30 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -8,6 +8,7 @@ test_description='git tag
 Tests for operations with tags.'
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY/lib-gpg.sh"
 
 # creating and listing lightweight tags:
 
@@ -585,24 +586,6 @@ test_expect_success \
 	test_cmp expect actual
 '
 
-# subsequent tests require gpg; check if it is available
-gpg --version >/dev/null 2>/dev/null
-if [ $? -eq 127 ]; then
-	say "# gpg not found - skipping tag signing and verification tests"
-else
-	# As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
-	# the gpg version 1.0.6 didn't parse trust packets correctly, so for
-	# that version, creation of signed tags using the generated key fails.
-	case "$(gpg --version)" in
-	'gpg (GnuPG) 1.0.6'*)
-		say "Skipping signed tag tests, because a bug in 1.0.6 version"
-		;;
-	*)
-		test_set_prereq GPG
-		;;
-	esac
-fi
-
 # trying to verify annotated non-signed tags:
 
 test_expect_success GPG \
@@ -625,16 +608,6 @@ test_expect_success GPG \
 
 # creating and verifying signed tags:
 
-# key generation info: gpg --homedir t/t7004 --gen-key
-# Type DSA and Elgamal, size 2048 bits, no expiration date.
-# Name and email: C O Mitter 
-# No password given, to enable non-interactive operation.
-
-cp -R "$TEST_DIRECTORY"/t7004 ./gpghome
-chmod 0700 gpghome
-GNUPGHOME="$(pwd)/gpghome"
-export GNUPGHOME
-
 get_tag_header signed-tag $commit commit $time >expect
 echo 'A signed tag message' >>expect
 echo '-----BEGIN PGP SIGNATURE-----' >>expect

From d542c72a8e7950dd943be51fc6e509ed37fbb4a2 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Wed, 19 Oct 2011 17:15:05 -0700
Subject: [PATCH 2230/3720] test "commit -S" and "log --show-signature"

Signed-off-by: Junio C Hamano 
---
 t/t7510-signed-commit.sh | 60 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100755 t/t7510-signed-commit.sh

diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
new file mode 100755
index 0000000000..5c7475d818
--- /dev/null
+++ b/t/t7510-signed-commit.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+test_description='signed commit tests'
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-gpg.sh"
+
+test_expect_success GPG 'create signed commits' '
+	echo 1 >file && git add file &&
+	test_tick && git commit -S -m initial &&
+	git tag initial &&
+	git branch side &&
+
+	echo 2 >file && test_tick && git commit -a -S -m second &&
+	git tag second &&
+
+	git checkout side &&
+	echo 3 >elif && git add elif &&
+	test_tick && git commit -m "third on side" &&
+
+	git checkout master &&
+	test_tick && git merge -S side &&
+	git tag merge &&
+
+	echo 4 >file && test_tick && git commit -a -m "fourth unsigned" &&
+	git tag fourth-unsigned &&
+
+	test_tick && git commit --amend -S -m "fourth signed"
+'
+
+test_expect_success GPG 'show signatures' '
+	(
+		for commit in initial second merge master
+		do
+			git show --pretty=short --show-signature $commit >actual &&
+			grep "Good signature from" actual || exit 1
+			! grep "BAD signature from" actual || exit 1
+			echo $commit OK
+		done
+	) &&
+	(
+		for commit in merge^2 fourth-unsigned
+		do
+			git show --pretty=short --show-signature $commit >actual &&
+			grep "Good signature from" actual && exit 1
+			! grep "BAD signature from" actual || exit 1
+			echo $commit OK
+		done
+	)
+'
+
+test_expect_success GPG 'detect fudged signature' '
+	git cat-file commit master >raw &&
+	sed -e "s/fourth signed/4th forged/" raw >forged &&
+	git hash-object -w -t commit forged >forged.commit &&
+	git show --pretty=short --show-signature $(cat forged.commit) >actual &&
+	grep "BAD signature from" actual &&
+	! grep "Good signature from" actual
+'
+
+test_done

From 0eba4d80cc7922b8577860cc02ccb26f7073a68c Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:41 +0200
Subject: [PATCH 2231/3720] Rename another local variable name -> refname

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/refs.c b/refs.c
index 7e6cea5458..f6752a489d 100644
--- a/refs.c
+++ b/refs.c
@@ -317,11 +317,11 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
 	if (dir) {
 		struct dirent *de;
 		int baselen = strlen(base);
-		char *ref = xmalloc(baselen + 257);
+		char *refname = xmalloc(baselen + 257);
 
-		memcpy(ref, base, baselen);
+		memcpy(refname, base, baselen);
 		if (baselen && base[baselen-1] != '/')
-			ref[baselen++] = '/';
+			refname[baselen++] = '/';
 
 		while ((de = readdir(dir)) != NULL) {
 			unsigned char sha1[20];
@@ -337,31 +337,31 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
 				continue;
 			if (has_extension(de->d_name, ".lock"))
 				continue;
-			memcpy(ref + baselen, de->d_name, namelen+1);
+			memcpy(refname + baselen, de->d_name, namelen+1);
 			refdir = *refs->name
-				? git_path_submodule(refs->name, "%s", ref)
-				: git_path("%s", ref);
+				? git_path_submodule(refs->name, "%s", refname)
+				: git_path("%s", refname);
 			if (stat(refdir, &st) < 0)
 				continue;
 			if (S_ISDIR(st.st_mode)) {
-				get_ref_dir(refs, ref, array);
+				get_ref_dir(refs, refname, array);
 				continue;
 			}
 			if (*refs->name) {
 				hashclr(sha1);
 				flag = 0;
-				if (resolve_gitlink_ref(refs->name, ref, sha1) < 0) {
+				if (resolve_gitlink_ref(refs->name, refname, sha1) < 0) {
 					hashclr(sha1);
 					flag |= REF_BROKEN;
 				}
 			} else
-				if (!resolve_ref(ref, sha1, 1, &flag)) {
+				if (!resolve_ref(refname, sha1, 1, &flag)) {
 					hashclr(sha1);
 					flag |= REF_BROKEN;
 				}
-			add_ref(ref, sha1, flag, array, NULL);
+			add_ref(refname, sha1, flag, array, NULL);
 		}
-		free(ref);
+		free(refname);
 		closedir(dir);
 	}
 }

From 117e8b6037ea48b8c72a72970f85ed6ed8530285 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:42 +0200
Subject: [PATCH 2232/3720] repack_without_ref(): remove temporary

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/refs.c b/refs.c
index f6752a489d..431d3c661d 100644
--- a/refs.c
+++ b/refs.c
@@ -1190,12 +1190,10 @@ static struct lock_file packlock;
 static int repack_without_ref(const char *refname)
 {
 	struct ref_array *packed;
-	struct ref_entry *ref;
 	int fd, i;
 
 	packed = get_packed_refs(get_ref_cache(NULL));
-	ref = search_ref_array(packed, refname);
-	if (ref == NULL)
+	if (search_ref_array(packed, refname) == NULL)
 		return 0;
 	fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
 	if (fd < 0) {
@@ -1206,8 +1204,7 @@ static int repack_without_ref(const char *refname)
 	for (i = 0; i < packed->nr; i++) {
 		char line[PATH_MAX + 100];
 		int len;
-
-		ref = packed->refs[i];
+		struct ref_entry *ref = packed->refs[i];
 
 		if (!strcmp(refname, ref->name))
 			continue;

From 011e9393ed442ecddc5c16e6776f78e543afb996 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:43 +0200
Subject: [PATCH 2233/3720] parse_ref_line(): add a check that the refname is
 properly formatted

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/refs.c b/refs.c
index 431d3c661d..752938c23c 100644
--- a/refs.c
+++ b/refs.c
@@ -51,6 +51,9 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 		return NULL;
 	line[len] = 0;
 
+	if (check_refname_format(line, REFNAME_ALLOW_ONELEVEL))
+		return NULL;
+
 	return line;
 }
 

From 6ac6c1f4b453b5bb90b27f273f9a143cc27b448d Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:44 +0200
Subject: [PATCH 2234/3720] create_ref_entry(): extract function from add_ref()

Separate the creation of the ref_entry from its addition to a ref_array.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 38 ++++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/refs.c b/refs.c
index 752938c23c..acb098c3d2 100644
--- a/refs.c
+++ b/refs.c
@@ -57,27 +57,33 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 	return line;
 }
 
+static struct ref_entry *create_ref_entry(const char *refname,
+					  const unsigned char *sha1, int flag)
+{
+	int len;
+	struct ref_entry *ref;
+
+	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
+		die("Reference has invalid format: '%s'", refname);
+	len = strlen(refname) + 1;
+	ref = xmalloc(sizeof(struct ref_entry) + len);
+	hashcpy(ref->sha1, sha1);
+	hashclr(ref->peeled);
+	memcpy(ref->name, refname, len);
+	ref->flag = flag;
+	return ref;
+}
+
 /* Add a ref_entry to the end of the ref_array (unsorted). */
 static void add_ref(const char *refname, const unsigned char *sha1,
 		    int flag, struct ref_array *refs,
-		    struct ref_entry **new_entry)
+		    struct ref_entry **new_ref)
 {
-	int len;
-	struct ref_entry *entry;
-
-	/* Allocate it and add it in.. */
-	len = strlen(refname) + 1;
-	entry = xmalloc(sizeof(struct ref_entry) + len);
-	hashcpy(entry->sha1, sha1);
-	hashclr(entry->peeled);
-	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
-		die("Reference has invalid format: '%s'", refname);
-	memcpy(entry->name, refname, len);
-	entry->flag = flag;
-	if (new_entry)
-		*new_entry = entry;
+	struct ref_entry *ref = create_ref_entry(refname, sha1, flag);
+	if (new_ref)
+		*new_ref = ref;
 	ALLOC_GROW(refs->refs, refs->nr + 1, refs->alloc);
-	refs->refs[refs->nr++] = entry;
+	refs->refs[refs->nr++] = ref;
 }
 
 static int ref_entry_cmp(const void *a, const void *b)

From 20be9176340fc1016112b09879c0e3d7a2307fd9 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:45 +0200
Subject: [PATCH 2235/3720] add_ref(): take a (struct ref_entry *) parameter

Take a pointer to the ref_entry to add to the array, rather than
creating the ref_entry within the function.  This opens the way to
having multiple kinds of ref_entries.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/refs.c b/refs.c
index acb098c3d2..ae9099300a 100644
--- a/refs.c
+++ b/refs.c
@@ -75,13 +75,8 @@ static struct ref_entry *create_ref_entry(const char *refname,
 }
 
 /* Add a ref_entry to the end of the ref_array (unsorted). */
-static void add_ref(const char *refname, const unsigned char *sha1,
-		    int flag, struct ref_array *refs,
-		    struct ref_entry **new_ref)
+static void add_ref(struct ref_array *refs, struct ref_entry *ref)
 {
-	struct ref_entry *ref = create_ref_entry(refname, sha1, flag);
-	if (new_ref)
-		*new_ref = ref;
 	ALLOC_GROW(refs->refs, refs->nr + 1, refs->alloc);
 	refs->refs[refs->nr++] = ref;
 }
@@ -266,7 +261,8 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 		refname = parse_ref_line(refline, sha1);
 		if (refname) {
-			add_ref(refname, sha1, flag, array, &last);
+			last = create_ref_entry(refname, sha1, flag);
+			add_ref(array, last);
 			continue;
 		}
 		if (last &&
@@ -281,7 +277,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
 {
-	add_ref(refname, sha1, flag, &extra_refs, NULL);
+	add_ref(&extra_refs, create_ref_entry(refname, sha1, flag));
 }
 
 void clear_extra_refs(void)
@@ -368,7 +364,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
 					hashclr(sha1);
 					flag |= REF_BROKEN;
 				}
-			add_ref(refname, sha1, flag, array, NULL);
+			add_ref(array, create_ref_entry(refname, sha1, flag));
 		}
 		free(refname);
 		closedir(dir);

From 7748941eaafb44dc1d9fb331fd5e0085a33de8f4 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:46 +0200
Subject: [PATCH 2236/3720] do_for_each_ref(): correctly terminate while
 processesing extra_refs

If the user-supplied function returns a nonzero value while processing
extra_refs, terminate without processing the rest of the list.

This probably has no practical importance, but makes the handling of
extra_refs a little bit more consistent with the handling of other
refs.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index ae9099300a..7aef76c717 100644
--- a/refs.c
+++ b/refs.c
@@ -706,8 +706,11 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
 
 	struct ref_array *extra = &extra_refs;
 
-	for (i = 0; i < extra->nr; i++)
+	for (i = 0; i < extra->nr; i++) {
 		retval = do_one_ref(base, fn, trim, flags, cb_data, extra->refs[i]);
+		if (retval)
+			goto end_each;
+	}
 
 	while (p < packed->nr && l < loose->nr) {
 		struct ref_entry *entry;

From 3a0faa27a0c213708f4bc34eae22573f8928b365 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:47 +0200
Subject: [PATCH 2237/3720] do_for_each_ref_in_array(): new function

Extract function do_for_each_ref_in_array() from do_for_each_ref().

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 39 +++++++++++++++++++++++----------------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/refs.c b/refs.c
index 7aef76c717..4e60edba2d 100644
--- a/refs.c
+++ b/refs.c
@@ -696,21 +696,31 @@ fallback:
 	return -1;
 }
 
+static int do_for_each_ref_in_array(struct ref_array *array, int offset,
+				    const char *base,
+				    each_ref_fn fn, int trim, int flags, void *cb_data)
+{
+	int i;
+	for (i = offset; i < array->nr; i++) {
+		int retval = do_one_ref(base, fn, trim, flags, cb_data, array->refs[i]);
+		if (retval)
+			return retval;
+	}
+	return 0;
+}
+
 static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn,
 			   int trim, int flags, void *cb_data)
 {
-	int retval = 0, i, p = 0, l = 0;
+	int retval = 0, p = 0, l = 0;
 	struct ref_cache *refs = get_ref_cache(submodule);
 	struct ref_array *packed = get_packed_refs(refs);
 	struct ref_array *loose = get_loose_refs(refs);
 
-	struct ref_array *extra = &extra_refs;
-
-	for (i = 0; i < extra->nr; i++) {
-		retval = do_one_ref(base, fn, trim, flags, cb_data, extra->refs[i]);
-		if (retval)
-			goto end_each;
-	}
+	retval = do_for_each_ref_in_array(&extra_refs, 0,
+					  base, fn, trim, flags, cb_data);
+	if (retval)
+		goto end_each;
 
 	while (p < packed->nr && l < loose->nr) {
 		struct ref_entry *entry;
@@ -730,14 +740,11 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
 	}
 
 	if (l < loose->nr) {
-		p = l;
-		packed = loose;
-	}
-
-	for (; p < packed->nr; p++) {
-		retval = do_one_ref(base, fn, trim, flags, cb_data, packed->refs[p]);
-		if (retval)
-			goto end_each;
+		retval = do_for_each_ref_in_array(loose, l,
+						  base, fn, trim, flags, cb_data);
+	} else {
+		retval = do_for_each_ref_in_array(packed, p,
+						  base, fn, trim, flags, cb_data);
 	}
 
 end_each:

From 782aee6c3813782a161c6d4e83386b9ecc5c01d8 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:49 +0200
Subject: [PATCH 2238/3720] repack_without_ref(): reimplement using
 do_for_each_ref_in_array()

It costs a bit of boilerplate, but it means that the function can be
ignorant of how cached refs are stored.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 46 ++++++++++++++++++++++++++++------------------
 1 file changed, 28 insertions(+), 18 deletions(-)

diff --git a/refs.c b/refs.c
index 4e60edba2d..38417b9e22 100644
--- a/refs.c
+++ b/refs.c
@@ -1200,36 +1200,46 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
 	return lock_ref_sha1_basic(refname, old_sha1, flags, NULL);
 }
 
+struct repack_without_ref_sb {
+	const char *refname;
+	int fd;
+};
+
+static int repack_without_ref_fn(const char *refname, const unsigned char *sha1,
+				 int flags, void *cb_data)
+{
+	struct repack_without_ref_sb *data = cb_data;
+	char line[PATH_MAX + 100];
+	int len;
+
+	if (!strcmp(data->refname, refname))
+		return 0;
+	len = snprintf(line, sizeof(line), "%s %s\n",
+		       sha1_to_hex(sha1), refname);
+	/* this should not happen but just being defensive */
+	if (len > sizeof(line))
+		die("too long a refname '%s'", refname);
+	write_or_die(data->fd, line, len);
+	return 0;
+}
+
 static struct lock_file packlock;
 
 static int repack_without_ref(const char *refname)
 {
+	struct repack_without_ref_sb data;
 	struct ref_array *packed;
-	int fd, i;
 
 	packed = get_packed_refs(get_ref_cache(NULL));
 	if (search_ref_array(packed, refname) == NULL)
 		return 0;
-	fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
-	if (fd < 0) {
+	data.refname = refname;
+	data.fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
+	if (data.fd < 0) {
 		unable_to_lock_error(git_path("packed-refs"), errno);
 		return error("cannot delete '%s' from packed refs", refname);
 	}
-
-	for (i = 0; i < packed->nr; i++) {
-		char line[PATH_MAX + 100];
-		int len;
-		struct ref_entry *ref = packed->refs[i];
-
-		if (!strcmp(refname, ref->name))
-			continue;
-		len = snprintf(line, sizeof(line), "%s %s\n",
-			       sha1_to_hex(ref->sha1), ref->name);
-		/* this should not happen but just being defensive */
-		if (len > sizeof(line))
-			die("too long a refname '%s'", ref->name);
-		write_or_die(fd, line, len);
-	}
+	do_for_each_ref_in_array(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
 	return commit_lock_file(&packlock);
 }
 

From 53699dc56be36a7237961b758c7e3ca5d0f21ee0 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:50 +0200
Subject: [PATCH 2239/3720] names_conflict(): new function, extracted from
 is_refname_available()

This costs an extra strlen() in the loop, but even that small price
will be clawed back in the next patch.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 43 +++++++++++++++++++++++++++++++------------
 1 file changed, 31 insertions(+), 12 deletions(-)

diff --git a/refs.c b/refs.c
index 38417b9e22..445dd6369f 100644
--- a/refs.c
+++ b/refs.c
@@ -1074,6 +1074,30 @@ static int remove_empty_directories(const char *file)
 	return result;
 }
 
+/*
+ * Return true iff refname1 and refname2 conflict with each other.
+ * Two reference names conflict if one of them exactly matches the
+ * leading components of the other; e.g., "foo/bar" conflicts with
+ * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
+ * "foo/barbados".
+ */
+static int names_conflict(const char *refname1, const char *refname2)
+{
+	int len1 = strlen(refname1);
+	int len2 = strlen(refname2);
+	int cmplen;
+	const char *lead;
+
+	if (len1 < len2) {
+		cmplen = len1;
+		lead = refname2;
+	} else {
+		cmplen = len2;
+		lead = refname1;
+	}
+	return !strncmp(refname1, refname2, cmplen) && lead[cmplen] == '/';
+}
+
 /*
  * Return true iff a reference named refname could be created without
  * conflicting with the name of an existing reference.  If oldrefname
@@ -1084,20 +1108,15 @@ static int remove_empty_directories(const char *file)
 static int is_refname_available(const char *refname, const char *oldrefname,
 				struct ref_array *array)
 {
-	int i, namlen = strlen(refname); /* e.g. 'foo/bar' */
+	int i;
 	for (i = 0; i < array->nr; i++ ) {
 		struct ref_entry *entry = array->refs[i];
-		/* entry->name could be 'foo' or 'foo/bar/baz' */
-		if (!oldrefname || strcmp(oldrefname, entry->name)) {
-			int len = strlen(entry->name);
-			int cmplen = (namlen < len) ? namlen : len;
-			const char *lead = (namlen < len) ? entry->name : refname;
-			if (!strncmp(refname, entry->name, cmplen) &&
-			    lead[cmplen] == '/') {
-				error("'%s' exists; cannot create '%s'",
-				      entry->name, refname);
-				return 0;
-			}
+		if (oldrefname && !strcmp(oldrefname, entry->name))
+			continue;
+		if (names_conflict(refname, entry->name)) {
+			error("'%s' exists; cannot create '%s'",
+			      entry->name, refname);
+			return 0;
 		}
 	}
 	return 1;

From 44db76087047c3899a6b0e5269e794d6dc165e12 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:51 +0200
Subject: [PATCH 2240/3720] names_conflict(): simplify implementation

Save a bunch of lines of code and a couple of strlen() calls.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/refs.c b/refs.c
index 445dd6369f..37bc002dec 100644
--- a/refs.c
+++ b/refs.c
@@ -1083,19 +1083,10 @@ static int remove_empty_directories(const char *file)
  */
 static int names_conflict(const char *refname1, const char *refname2)
 {
-	int len1 = strlen(refname1);
-	int len2 = strlen(refname2);
-	int cmplen;
-	const char *lead;
-
-	if (len1 < len2) {
-		cmplen = len1;
-		lead = refname2;
-	} else {
-		cmplen = len2;
-		lead = refname1;
-	}
-	return !strncmp(refname1, refname2, cmplen) && lead[cmplen] == '/';
+	for (; *refname1 && *refname1 == *refname2; refname1++, refname2++)
+		;
+	return (*refname1 == '\0' && *refname2 == '/')
+		|| (*refname1 == '/' && *refname2 == '\0');
 }
 
 /*

From caa80697e2189695592c03aa7d8832dcda09ea30 Mon Sep 17 00:00:00 2001
From: Michael Haggerty 
Date: Wed, 19 Oct 2011 23:44:52 +0200
Subject: [PATCH 2241/3720] is_refname_available(): reimplement using
 do_for_each_ref_in_array()

This implementation will survive upcoming changes to the ref_array
data structure.

Signed-off-by: Michael Haggerty 
Signed-off-by: Junio C Hamano 
---
 refs.c | 44 ++++++++++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/refs.c b/refs.c
index 37bc002dec..59f1db2952 100644
--- a/refs.c
+++ b/refs.c
@@ -1089,6 +1089,25 @@ static int names_conflict(const char *refname1, const char *refname2)
 		|| (*refname1 == '/' && *refname2 == '\0');
 }
 
+struct name_conflict_cb {
+       const char *refname;
+       const char *oldrefname;
+       const char *conflicting_refname;
+};
+
+static int name_conflict_fn(const char *existingrefname, const unsigned char *sha1,
+			    int flags, void *cb_data)
+{
+       struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data;
+       if (data->oldrefname && !strcmp(data->oldrefname, existingrefname))
+	       return 0;
+       if (names_conflict(data->refname, existingrefname)) {
+	       data->conflicting_refname = existingrefname;
+	       return 1;
+       }
+       return 0;
+}
+
 /*
  * Return true iff a reference named refname could be created without
  * conflicting with the name of an existing reference.  If oldrefname
@@ -1099,18 +1118,19 @@ static int names_conflict(const char *refname1, const char *refname2)
 static int is_refname_available(const char *refname, const char *oldrefname,
 				struct ref_array *array)
 {
-	int i;
-	for (i = 0; i < array->nr; i++ ) {
-		struct ref_entry *entry = array->refs[i];
-		if (oldrefname && !strcmp(oldrefname, entry->name))
-			continue;
-		if (names_conflict(refname, entry->name)) {
-			error("'%s' exists; cannot create '%s'",
-			      entry->name, refname);
-			return 0;
-		}
-	}
-	return 1;
+       struct name_conflict_cb data;
+       data.refname = refname;
+       data.oldrefname = oldrefname;
+       data.conflicting_refname = NULL;
+
+       if (do_for_each_ref_in_array(array, 0, "", name_conflict_fn,
+				    0, DO_FOR_EACH_INCLUDE_BROKEN,
+				    &data)) {
+	       error("'%s' exists; cannot create '%s'",
+		     data.conflicting_refname, refname);
+	       return 0;
+       }
+       return 1;
 }
 
 static struct ref_lock *lock_ref_sha1_basic(const char *refname,

From 33a11a20eb7610771268e34211509cbbdee76b1e Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Thu, 20 Oct 2011 11:37:59 -0700
Subject: [PATCH 2242/3720] parse_signed_commit: really use the entire commit
 log message

... even beyond the first NUL in the buffer, when checking the commit
against the detached signature in the header.

Signed-off-by: Junio C Hamano 
---
 commit.c                 | 21 ++++++++++++---------
 t/t7510-signed-commit.sh | 21 ++++++++++++++++-----
 2 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/commit.c b/commit.c
index 93045a2cda..09693f78d9 100644
--- a/commit.c
+++ b/commit.c
@@ -854,28 +854,31 @@ int parse_signed_commit(const unsigned char *sha1,
 	unsigned long size;
 	enum object_type type;
 	char *buffer = read_sha1_file(sha1, &type, &size);
-	int in_header, saw_signature = -1;
-	char *line;
+	int saw_signature = -1;
+	char *line, *tail;
 
 	if (!buffer || type != OBJ_COMMIT)
 		goto cleanup;
 
 	line = buffer;
-	in_header = 1;
+	tail = buffer + size;
 	saw_signature = 0;
-	while (*line) {
-		char *next = strchrnul(line, '\n');
-		if (*next)
+	while (line < tail) {
+		char *next = memchr(line, '\n', tail - line);
+		if (!next)
+			next = tail;
+		else
 			next++;
-		if (in_header && !prefixcmp(line, gpg_sig_header)) {
+		if (!prefixcmp(line, gpg_sig_header)) {
 			const char *sig = line + gpg_sig_header_len;
 			strbuf_add(signature, sig, next - sig);
 			saw_signature = 1;
 		} else {
+			if (*line == '\n')
+				/* dump the whole remainder of the buffer */
+				next = tail;
 			strbuf_add(payload, line, next - line);
 		}
-		if (*line == '\n')
-			in_header = 0;
 		line = next;
 	}
  cleanup:
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 5c7475d818..30401ced07 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -50,11 +50,22 @@ test_expect_success GPG 'show signatures' '
 
 test_expect_success GPG 'detect fudged signature' '
 	git cat-file commit master >raw &&
-	sed -e "s/fourth signed/4th forged/" raw >forged &&
-	git hash-object -w -t commit forged >forged.commit &&
-	git show --pretty=short --show-signature $(cat forged.commit) >actual &&
-	grep "BAD signature from" actual &&
-	! grep "Good signature from" actual
+
+	sed -e "s/fourth signed/4th forged/" raw >forged1 &&
+	git hash-object -w -t commit forged1 >forged1.commit &&
+	git show --pretty=short --show-signature $(cat forged1.commit) >actual1 &&
+	grep "BAD signature from" actual1 &&
+	! grep "Good signature from" actual1
+'
+
+test_expect_success GPG 'detect fudged signature with NUL' '
+	git cat-file commit master >raw &&
+	cat raw >forged2 &&
+	echo Qwik | tr "Q" "\000" >>forged2 &&
+	git hash-object -w -t commit forged2 >forged2.commit &&
+	git show --pretty=short --show-signature $(cat forged2.commit) >actual2 &&
+	grep "BAD signature from" actual2 &&
+	! grep "Good signature from" actual2
 '
 
 test_done

From 4aa8b8c82837a7f4aa742ba49f3461d827dff4ee Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2243/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index e1da468766..f440fcd23c 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 8c1370f81b..9a06730170 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 dry_run=
 while :
@@ -105,7 +106,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -270,7 +276,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From b7ba1b3b15166e5a734ab893d46c2354c1cd13a9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2244/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5426d775a5..20138797ef 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -677,6 +677,7 @@ branch..rebase::
 	When true, rebase the branch  on top of the fetched branch,
 	instead of merging the default branch from the default remote when
 	"git pull" is run.
+	When the value is `interactive`, the rebase is run in interactive mode.
 	*NOTE*: this is a possibly dangerous operation; do *not* use
 	it unless you understand the implications (see linkgit:git-rebase[1]
 	for details).
diff --git a/git-pull.sh b/git-pull.sh
index 9a06730170..6e3d0a9cd8 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 dry_run=
 while :
 do

From 5f549aa2f78314ac37bbd436c8f80aea4c752e07 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Fri, 21 Oct 2011 21:06:02 -0700
Subject: [PATCH 2245/3720] pretty: %G[?GS] placeholders

Add new placeholders related to the GPG signature on signed commits.

 - %GG to show the raw verification message from GPG;
 - %G? to show either "G" for Good, "B" for Bad;
 - %GS to show the name of the signer.

Signed-off-by: Junio C Hamano 
---
 pretty.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/pretty.c b/pretty.c
index f45eb54e4c..392d656595 100644
--- a/pretty.c
+++ b/pretty.c
@@ -9,6 +9,7 @@
 #include "notes.h"
 #include "color.h"
 #include "reflog-walk.h"
+#include "gpg-interface.h"
 
 static char *user_format;
 static struct cmt_fmt_map {
@@ -640,6 +641,12 @@ struct format_commit_context {
 	const struct pretty_print_context *pretty_ctx;
 	unsigned commit_header_parsed:1;
 	unsigned commit_message_parsed:1;
+	unsigned commit_signature_parsed:1;
+	struct {
+		char *gpg_output;
+		char good_bad;
+		char *signer;
+	} signature;
 	char *message;
 	size_t width, indent1, indent2;
 
@@ -822,6 +829,59 @@ static void rewrap_message_tail(struct strbuf *sb,
 	c->indent2 = new_indent2;
 }
 
+static struct {
+	char result;
+	const char *check;
+} signature_check[] = {
+	{ 'G', ": Good signature from " },
+	{ 'B', ": BAD signature from " },
+};
+
+static void parse_signature_lines(struct format_commit_context *ctx)
+{
+	const char *buf = ctx->signature.gpg_output;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
+		const char *found = strstr(buf, signature_check[i].check);
+		const char *next;
+		if (!found)
+			continue;
+		ctx->signature.good_bad = signature_check[i].result;
+		found += strlen(signature_check[i].check);
+		next = strchrnul(found, '\n');
+		ctx->signature.signer = xmemdupz(found, next - found);
+		break;
+	}
+}
+
+static void parse_commit_signature(struct format_commit_context *ctx)
+{
+	struct strbuf payload = STRBUF_INIT;
+	struct strbuf signature = STRBUF_INIT;
+	struct strbuf gpg_output = STRBUF_INIT;
+	int status;
+
+	ctx->commit_signature_parsed = 1;
+
+	if (parse_signed_commit(ctx->commit->object.sha1,
+				&payload, &signature) <= 0)
+		goto out;
+	status = verify_signed_buffer(payload.buf, payload.len,
+				      signature.buf, signature.len,
+				      &gpg_output);
+	if (status && !gpg_output.len)
+		goto out;
+	ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
+	parse_signature_lines(ctx);
+
+ out:
+	strbuf_release(&gpg_output);
+	strbuf_release(&payload);
+	strbuf_release(&signature);
+}
+
+
 static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 				void *context)
 {
@@ -974,6 +1034,30 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 		return 0;
 	}
 
+	if (placeholder[0] == 'G') {
+		if (!c->commit_signature_parsed)
+			parse_commit_signature(c);
+		switch (placeholder[1]) {
+		case 'G':
+			if (c->signature.gpg_output)
+				strbuf_addstr(sb, c->signature.gpg_output);
+			break;
+		case '?':
+			switch (c->signature.good_bad) {
+			case 'G':
+			case 'B':
+				strbuf_addch(sb, c->signature.good_bad);
+			}
+			break;
+		case 'S':
+			if (c->signature.signer)
+				strbuf_addstr(sb, c->signature.signer);
+			break;
+		}
+		return 2;
+	}
+
+
 	/* For the rest we have to parse the commit header. */
 	if (!c->commit_header_parsed)
 		parse_commit_header(c);
@@ -1114,6 +1198,8 @@ void format_commit_message(const struct commit *commit,
 
 	if (context.message != commit->buffer)
 		free(context.message);
+	free(context.signature.gpg_output);
+	free(context.signature.signer);
 }
 
 static void pp_header(const struct pretty_print_context *pp,

From b9e6e429378a7763025d1e2f5a1e19d4166ffa05 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra 
Date: Sun, 23 Oct 2011 00:43:42 +0530
Subject: [PATCH 2246/3720] revert: free msg in format_todo()

Memory allocated to the fields of msg by get_message() isn't freed.
This is potentially a big leak, because fresh memory is allocated to
store the commit message for each commit.  Fix this using
free_message().

Reported-by: Jonathan Nieder 
Signed-off-by: Ramkumar Ramachandra 
Signed-off-by: Junio C Hamano 
---
 builtin/revert.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/revert.c b/builtin/revert.c
index 87df70edc3..a6f2ea7e27 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -689,6 +689,7 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
 		if (get_message(cur->item, &msg))
 			return error(_("Cannot get commit message for %s"), sha1_abbrev);
 		strbuf_addf(buf, "%s %s %s\n", action_str, sha1_abbrev, msg.subject);
+		free_message(&msg);
 	}
 	return 0;
 }

From e6010ee77afa781cdb910c7b15762cca27c4bec9 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra 
Date: Sun, 23 Oct 2011 00:43:43 +0530
Subject: [PATCH 2247/3720] revert: simplify getting commit subject in
 format_todo()

format_todo() calls get_message(), but uses only the subject line of
the commit message.  Save work and unnecessary memory allocations by
using find_commit_subject() instead.

Suggested-by: Jonathan Nieder 
Signed-off-by: Ramkumar Ramachandra 
Signed-off-by: Junio C Hamano 
---
 builtin/revert.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/builtin/revert.c b/builtin/revert.c
index a6f2ea7e27..efa8d009a1 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -680,16 +680,16 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
 		struct replay_opts *opts)
 {
 	struct commit_list *cur = NULL;
-	struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
 	const char *sha1_abbrev = NULL;
 	const char *action_str = opts->action == REVERT ? "revert" : "pick";
+	const char *subject;
+	int subject_len;
 
 	for (cur = todo_list; cur; cur = cur->next) {
 		sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
-		if (get_message(cur->item, &msg))
-			return error(_("Cannot get commit message for %s"), sha1_abbrev);
-		strbuf_addf(buf, "%s %s %s\n", action_str, sha1_abbrev, msg.subject);
-		free_message(&msg);
+		subject_len = find_commit_subject(cur->item->buffer, &subject);
+		strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
+			subject_len, subject);
 	}
 	return 0;
 }

From 300f5e81b25161bc7da99bf60171a1c9d65eb3d8 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra 
Date: Sun, 23 Oct 2011 00:43:44 +0530
Subject: [PATCH 2248/3720] revert: make commit subjects in insn sheet optional

Change the instruction sheet format subtly so that the subject of the
commit message that follows the object name is optional.  As a result,
an instruction sheet like this is now perfectly valid:

  pick 35b0426
  pick fbd5bbcbc2e
  pick 7362160f

While at it, also fix a bug: currently, we use a commit-id-shaped
buffer to store the word after "pick" in '.git/sequencer/todo'.  This
is both wasteful and wrong because it places an artificial limit on
the line length.  Eliminate the need for the buffer altogether, and
add a test demonstrating this.

[jc: simplify parsing]

Suggested-by: Jonathan Nieder 
Helped-by: Junio C Hamano 
Signed-off-by: Ramkumar Ramachandra 
Signed-off-by: Junio C Hamano 
---
 builtin/revert.c                | 37 ++++++++++++++-------------------
 t/t3510-cherry-pick-sequence.sh | 28 +++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/builtin/revert.c b/builtin/revert.c
index efa8d009a1..14462ca526 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -694,31 +694,27 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
 	return 0;
 }
 
-static struct commit *parse_insn_line(char *start, struct replay_opts *opts)
+static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
 {
 	unsigned char commit_sha1[20];
-	char sha1_abbrev[40];
 	enum replay_action action;
-	int insn_len = 0;
-	char *p, *q;
+	char *end_of_object_name;
+	int saved, status;
 
-	if (!prefixcmp(start, "pick ")) {
+	if (!prefixcmp(bol, "pick ")) {
 		action = CHERRY_PICK;
-		insn_len = strlen("pick");
-		p = start + insn_len + 1;
-	} else if (!prefixcmp(start, "revert ")) {
+		bol += strlen("pick ");
+	} else if (!prefixcmp(bol, "revert ")) {
 		action = REVERT;
-		insn_len = strlen("revert");
-		p = start + insn_len + 1;
+		bol += strlen("revert ");
 	} else
 		return NULL;
 
-	q = strchr(p, ' ');
-	if (!q)
-		return NULL;
-	q++;
-
-	strlcpy(sha1_abbrev, p, q - p);
+	end_of_object_name = bol + strcspn(bol, " \n");
+	saved = *end_of_object_name;
+	*end_of_object_name = '\0';
+	status = get_sha1(bol, commit_sha1);
+	*end_of_object_name = saved;
 
 	/*
 	 * Verify that the action matches up with the one in
@@ -731,7 +727,7 @@ static struct commit *parse_insn_line(char *start, struct replay_opts *opts)
 		return NULL;
 	}
 
-	if (get_sha1(sha1_abbrev, commit_sha1) < 0)
+	if (status < 0)
 		return NULL;
 
 	return lookup_commit_reference(commit_sha1);
@@ -746,13 +742,12 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
 	int i;
 
 	for (i = 1; *p; i++) {
-		commit = parse_insn_line(p, opts);
+		char *eol = strchrnul(p, '\n');
+		commit = parse_insn_line(p, eol, opts);
 		if (!commit)
 			return error(_("Could not parse line %d."), i);
 		next = commit_list_append(commit, next);
-		p = strchrnul(p, '\n');
-		if (*p)
-			p++;
+		p = *eol ? eol + 1 : eol;
 	}
 	if (!*todo_list)
 		return error(_("No commits parsed."));
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 3bca2b3dd5..39b55c13fa 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -12,6 +12,9 @@ test_description='Test cherry-pick continuation features
 
 . ./test-lib.sh
 
+# Repeat first match 10 times
+_r10='\1\1\1\1\1\1\1\1\1\1'
+
 pristine_detach () {
 	git cherry-pick --reset &&
 	git checkout -f "$1^0" &&
@@ -211,4 +214,29 @@ test_expect_success 'malformed instruction sheet 2' '
 	test_must_fail git cherry-pick --continue
 '
 
+test_expect_success 'malformed instruction sheet 3' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick base..anotherpick &&
+	echo "resolved" >foo &&
+	git add foo &&
+	git commit &&
+	sed "s/pick \([0-9a-f]*\)/pick $_r10/" .git/sequencer/todo >new_sheet &&
+	cp new_sheet .git/sequencer/todo &&
+	test_must_fail git cherry-pick --continue
+'
+
+test_expect_success 'commit descriptions in insn sheet are optional' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick base..anotherpick &&
+	echo "c" >foo &&
+	git add foo &&
+	git commit &&
+	cut -d" " -f1,2 .git/sequencer/todo >new_sheet &&
+	cp new_sheet .git/sequencer/todo &&
+	git cherry-pick --continue &&
+	test_path_is_missing .git/sequencer &&
+	git rev-list HEAD >commits
+	test_line_count = 4 commits
+'
+
 test_done

From 755b65dac0355edca3004bad2103a60033ab1986 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra 
Date: Sun, 23 Oct 2011 00:43:45 +0530
Subject: [PATCH 2249/3720] revert: allow mixed pick and revert instructions

Parse the instruction sheet in '.git/sequencer/todo' as a list of
(action, operand) pairs, instead of assuming that all instructions use
the same action.  Now you can do:

  pick fdc0b12 picked
  revert 965fed4 anotherpick

For cherry-pick and revert, this means that a 'git cherry-pick
--continue' can continue an ongoing revert operation and viceversa.
This patch lays the foundation for extending the parser to support
more actions so 'git rebase -i' can reuse this machinery in the
future.  While at it, also improve the error messages reported by the
insn sheet parser.

Helped-by: Jonathan Nieder 
Acked-by: Jonathan Nieder 
Signed-off-by: Ramkumar Ramachandra 
Signed-off-by: Junio C Hamano 
---
 builtin/revert.c                | 132 ++++++++++++++++----------------
 sequencer.h                     |   8 ++
 t/t3510-cherry-pick-sequence.sh |  58 ++++++++++++++
 3 files changed, 130 insertions(+), 68 deletions(-)

diff --git a/builtin/revert.c b/builtin/revert.c
index 14462ca526..8c3e4fc6f6 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -39,7 +39,6 @@ static const char * const cherry_pick_usage[] = {
 	NULL
 };
 
-enum replay_action { REVERT, CHERRY_PICK };
 enum replay_subcommand { REPLAY_NONE, REPLAY_RESET, REPLAY_CONTINUE };
 
 struct replay_opts {
@@ -68,14 +67,14 @@ struct replay_opts {
 
 static const char *action_name(const struct replay_opts *opts)
 {
-	return opts->action == REVERT ? "revert" : "cherry-pick";
+	return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
 }
 
 static char *get_encoding(const char *message);
 
 static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
 {
-	return opts->action == REVERT ? revert_usage : cherry_pick_usage;
+	return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
 }
 
 static int option_parse_x(const struct option *opt,
@@ -152,7 +151,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 	};
 
-	if (opts->action == CHERRY_PICK) {
+	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
@@ -348,7 +347,7 @@ static int error_dirty_index(struct replay_opts *opts)
 		return error_resolve_conflict(action_name(opts));
 
 	/* Different translation strings for cherry-pick and revert */
-	if (opts->action == CHERRY_PICK)
+	if (opts->action == REPLAY_PICK)
 		error(_("Your local changes would be overwritten by cherry-pick."));
 	else
 		error(_("Your local changes would be overwritten by revert."));
@@ -452,7 +451,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 	return run_command_v_opt(args, RUN_GIT_CMD);
 }
 
-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
+static int do_pick_commit(struct commit *commit, enum replay_action action,
+			struct replay_opts *opts)
 {
 	unsigned char head[20];
 	struct commit *base, *next, *parent;
@@ -527,7 +527,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 
 	defmsg = git_pathdup("MERGE_MSG");
 
-	if (opts->action == REVERT) {
+	if (action == REPLAY_REVERT) {
 		base = commit;
 		base_label = msg.label;
 		next = parent;
@@ -568,7 +568,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		}
 	}
 
-	if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REVERT) {
+	if (!opts->strategy || !strcmp(opts->strategy, "recursive") || action == REPLAY_REVERT) {
 		res = do_recursive_merge(base, next, base_label, next_label,
 					 head, &msgbuf, opts);
 		write_message(&msgbuf, defmsg);
@@ -592,11 +592,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 	 * However, if the merge did not even start, then we don't want to
 	 * write it at all.
 	 */
-	if (opts->action == CHERRY_PICK && !opts->no_commit && (res == 0 || res == 1))
+	if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1))
 		write_cherry_pick_head(commit);
 
 	if (res) {
-		error(opts->action == REVERT
+		error(action == REPLAY_REVERT
 		      ? _("could not revert %s... %s")
 		      : _("could not apply %s... %s"),
 		      find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
@@ -620,7 +620,7 @@ static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)
 
 	init_revisions(revs, NULL);
 	revs->no_walk = 1;
-	if (opts->action != REVERT)
+	if (opts->action != REPLAY_REVERT)
 		revs->reverse = 1;
 
 	argc = setup_revisions(opts->commit_argc, opts->commit_argv, revs, NULL);
@@ -666,49 +666,53 @@ static void read_and_refresh_cache(struct replay_opts *opts)
  *     assert(commit_list_count(list) == 2);
  *     return list;
  */
-static struct commit_list **commit_list_append(struct commit *commit,
-					       struct commit_list **next)
+static struct replay_insn_list **replay_insn_list_append(enum replay_action action,
+						struct commit *operand,
+						struct replay_insn_list **next)
 {
-	struct commit_list *new = xmalloc(sizeof(struct commit_list));
-	new->item = commit;
+	struct replay_insn_list *new = xmalloc(sizeof(*new));
+	new->action = action;
+	new->operand = operand;
 	*next = new;
 	new->next = NULL;
 	return &new->next;
 }
 
-static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
-		struct replay_opts *opts)
+static int format_todo(struct strbuf *buf, struct replay_insn_list *todo_list)
 {
-	struct commit_list *cur = NULL;
-	const char *sha1_abbrev = NULL;
-	const char *action_str = opts->action == REVERT ? "revert" : "pick";
-	const char *subject;
-	int subject_len;
+	struct replay_insn_list *cur;
 
 	for (cur = todo_list; cur; cur = cur->next) {
-		sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
-		subject_len = find_commit_subject(cur->item->buffer, &subject);
+		const char *sha1_abbrev, *action_str, *subject;
+		int subject_len;
+
+		action_str = cur->action == REPLAY_REVERT ? "revert" : "pick";
+		sha1_abbrev = find_unique_abbrev(cur->operand->object.sha1, DEFAULT_ABBREV);
+		subject_len = find_commit_subject(cur->operand->buffer, &subject);
 		strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
 			subject_len, subject);
 	}
 	return 0;
 }
 
-static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
+static int parse_insn_line(char *bol, char *eol, struct replay_insn_list *item)
 {
 	unsigned char commit_sha1[20];
-	enum replay_action action;
 	char *end_of_object_name;
 	int saved, status;
 
 	if (!prefixcmp(bol, "pick ")) {
-		action = CHERRY_PICK;
+		item->action = REPLAY_PICK;
 		bol += strlen("pick ");
 	} else if (!prefixcmp(bol, "revert ")) {
-		action = REVERT;
+		item->action = REPLAY_REVERT;
 		bol += strlen("revert ");
-	} else
-		return NULL;
+	} else {
+		size_t len = strchrnul(bol, '\n') - bol;
+		if (len > 255)
+			len = 255;
+		return error(_("Unrecognized action: %.*s"), (int)len, bol);
+	}
 
 	end_of_object_name = bol + strcspn(bol, " \n");
 	saved = *end_of_object_name;
@@ -716,37 +720,29 @@ static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *
 	status = get_sha1(bol, commit_sha1);
 	*end_of_object_name = saved;
 
-	/*
-	 * Verify that the action matches up with the one in
-	 * opts; we don't support arbitrary instructions
-	 */
-	if (action != opts->action) {
-		const char *action_str;
-		action_str = action == REVERT ? "revert" : "cherry-pick";
-		error(_("Cannot %s during a %s"), action_str, action_name(opts));
-		return NULL;
-	}
-
 	if (status < 0)
-		return NULL;
+		return error(_("Malformed object name: %s"), bol);
 
-	return lookup_commit_reference(commit_sha1);
+	item->operand = lookup_commit_reference(commit_sha1);
+	if (!item->operand)
+		return error(_("Not a valid commit: %s"), bol);
+
+	item->next = NULL;
+	return 0;
 }
 
-static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
-			struct replay_opts *opts)
+static int parse_insn_buffer(char *buf, struct replay_insn_list **todo_list)
 {
-	struct commit_list **next = todo_list;
-	struct commit *commit;
+	struct replay_insn_list **next = todo_list;
+	struct replay_insn_list item = {0, NULL, NULL};
 	char *p = buf;
 	int i;
 
 	for (i = 1; *p; i++) {
 		char *eol = strchrnul(p, '\n');
-		commit = parse_insn_line(p, eol, opts);
-		if (!commit)
-			return error(_("Could not parse line %d."), i);
-		next = commit_list_append(commit, next);
+		if (parse_insn_line(p, eol, &item) < 0)
+			return error(_("on line %d."), i);
+		next = replay_insn_list_append(item.action, item.operand, next);
 		p = *eol ? eol + 1 : eol;
 	}
 	if (!*todo_list)
@@ -754,8 +750,7 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
 	return 0;
 }
 
-static void read_populate_todo(struct commit_list **todo_list,
-			struct replay_opts *opts)
+static void read_populate_todo(struct replay_insn_list **todo_list)
 {
 	const char *todo_file = git_path(SEQ_TODO_FILE);
 	struct strbuf buf = STRBUF_INIT;
@@ -771,7 +766,7 @@ static void read_populate_todo(struct commit_list **todo_list,
 	}
 	close(fd);
 
-	res = parse_insn_buffer(buf.buf, todo_list, opts);
+	res = parse_insn_buffer(buf.buf, todo_list);
 	strbuf_release(&buf);
 	if (res)
 		die(_("Unusable instruction sheet: %s"), todo_file);
@@ -820,18 +815,18 @@ static void read_populate_opts(struct replay_opts **opts_ptr)
 		die(_("Malformed options sheet: %s"), opts_file);
 }
 
-static void walk_revs_populate_todo(struct commit_list **todo_list,
+static void walk_revs_populate_todo(struct replay_insn_list **todo_list,
 				struct replay_opts *opts)
 {
 	struct rev_info revs;
 	struct commit *commit;
-	struct commit_list **next;
+	struct replay_insn_list **next;
 
 	prepare_revs(&revs, opts);
 
 	next = todo_list;
 	while ((commit = get_revision(&revs)))
-		next = commit_list_append(commit, next);
+		next = replay_insn_list_append(opts->action, commit, next);
 }
 
 static int create_seq_dir(void)
@@ -860,7 +855,7 @@ static void save_head(const char *head)
 		die(_("Error wrapping up %s."), head_file);
 }
 
-static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
+static void save_todo(struct replay_insn_list *todo_list)
 {
 	const char *todo_file = git_path(SEQ_TODO_FILE);
 	static struct lock_file todo_lock;
@@ -868,7 +863,7 @@ static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
 	int fd;
 
 	fd = hold_lock_file_for_update(&todo_lock, todo_file, LOCK_DIE_ON_ERROR);
-	if (format_todo(&buf, todo_list, opts) < 0)
+	if (format_todo(&buf, todo_list) < 0)
 		die(_("Could not format %s."), todo_file);
 	if (write_in_full(fd, buf.buf, buf.len) < 0) {
 		strbuf_release(&buf);
@@ -912,9 +907,10 @@ static void save_opts(struct replay_opts *opts)
 	}
 }
 
-static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
+static int pick_commits(struct replay_insn_list *todo_list,
+			struct replay_opts *opts)
 {
-	struct commit_list *cur;
+	struct replay_insn_list *cur;
 	int res;
 
 	setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
@@ -924,8 +920,8 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
 	read_and_refresh_cache(opts);
 
 	for (cur = todo_list; cur; cur = cur->next) {
-		save_todo(cur, opts);
-		res = do_pick_commit(cur->item, opts);
+		save_todo(cur);
+		res = do_pick_commit(cur->operand, cur->action, opts);
 		if (res) {
 			if (!cur->next)
 				/*
@@ -950,7 +946,7 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
 
 static int pick_revisions(struct replay_opts *opts)
 {
-	struct commit_list *todo_list = NULL;
+	struct replay_insn_list *todo_list = NULL;
 	unsigned char sha1[20];
 
 	read_and_refresh_cache(opts);
@@ -967,7 +963,7 @@ static int pick_revisions(struct replay_opts *opts)
 		if (!file_exists(git_path(SEQ_TODO_FILE)))
 			goto error;
 		read_populate_opts(&opts);
-		read_populate_todo(&todo_list, opts);
+		read_populate_todo(&todo_list);
 
 		/* Verify that the conflict has been resolved */
 		if (!index_differs_from("HEAD", 0))
@@ -987,7 +983,7 @@ static int pick_revisions(struct replay_opts *opts)
 			return -1;
 		}
 		if (get_sha1("HEAD", sha1)) {
-			if (opts->action == REVERT)
+			if (opts->action == REPLAY_REVERT)
 				return error(_("Can't revert as initial commit"));
 			return error(_("Can't cherry-pick into empty head"));
 		}
@@ -1007,7 +1003,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
 	memset(&opts, 0, sizeof(opts));
 	if (isatty(0))
 		opts.edit = 1;
-	opts.action = REVERT;
+	opts.action = REPLAY_REVERT;
 	git_config(git_default_config, NULL);
 	parse_args(argc, argv, &opts);
 	res = pick_revisions(&opts);
@@ -1022,7 +1018,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
 	int res;
 
 	memset(&opts, 0, sizeof(opts));
-	opts.action = CHERRY_PICK;
+	opts.action = REPLAY_PICK;
 	git_config(git_default_config, NULL);
 	parse_args(argc, argv, &opts);
 	res = pick_revisions(&opts);
diff --git a/sequencer.h b/sequencer.h
index 905d295012..f4db257a5b 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -7,6 +7,14 @@
 #define SEQ_TODO_FILE	"sequencer/todo"
 #define SEQ_OPTS_FILE	"sequencer/opts"
 
+enum replay_action { REPLAY_REVERT, REPLAY_PICK };
+
+struct replay_insn_list {
+	enum replay_action action;
+	struct commit *operand;
+	struct replay_insn_list *next;
+};
+
 /*
  * Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring
  * any errors.  Intended to be used by 'git reset'.
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 39b55c13fa..4b122441d0 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -239,4 +239,62 @@ test_expect_success 'commit descriptions in insn sheet are optional' '
 	test_line_count = 4 commits
 '
 
+test_expect_success 'revert --continue continues after cherry-pick' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick base..anotherpick &&
+	echo "c" >foo &&
+	git add foo &&
+	git commit &&
+	git revert --continue &&
+	test_path_is_missing .git/sequencer &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$_x40/OBJID/g"
+	} >actual &&
+	cat >expect <<-\EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_cmp expect actual
+'
+
+test_expect_success 'mixed pick and revert instructions' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick base..anotherpick &&
+	echo "c" >foo &&
+	git add foo &&
+	git commit &&
+	oldsha=`git rev-parse --short HEAD~1` &&
+	echo "revert $oldsha unrelatedpick" >>.git/sequencer/todo &&
+	git cherry-pick --continue &&
+	test_path_is_missing .git/sequencer &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$_x40/OBJID/g"
+	} >actual &&
+	cat >expect <<-\EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_cmp expect actual
+'
+
 test_done

From 6a156fdea266d26f4de083ae920a569179d2c893 Mon Sep 17 00:00:00 2001
From: Jonathan Nieder 
Date: Sun, 23 Oct 2011 00:43:46 +0530
Subject: [PATCH 2250/3720] revert: simplify communicating command-line
 arguments

Currently, command-line arguments are communicated using (argc, argv)
until a prepare_revs() turns it into a terse structure.  However,
since we plan to expose the cherry-picking machinery through a public
API in the future, we want callers to be able to call in with a
filled-in structure.  For the revert builtin, this means that the
chief argument parser, parse_args(), should parse into such a
structure.  Make this change.

[rr: minor improvements, commit message]

Signed-off-by: Ramkumar Ramachandra 
Signed-off-by: Jonathan Nieder 
Signed-off-by: Junio C Hamano 
---
 builtin/revert.c | 53 ++++++++++++++++++++++++++----------------------
 1 file changed, 29 insertions(+), 24 deletions(-)

diff --git a/builtin/revert.c b/builtin/revert.c
index 8c3e4fc6f6..df9459b6be 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -54,13 +54,14 @@ struct replay_opts {
 	int allow_rerere_auto;
 
 	int mainline;
-	int commit_argc;
-	const char **commit_argv;
 
 	/* Merge strategy */
 	const char *strategy;
 	const char **xopts;
 	size_t xopts_nr, xopts_alloc;
+
+	/* Only used by REPLAY_NONE */
+	struct rev_info *revs;
 };
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@@ -161,9 +162,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 			die(_("program error"));
 	}
 
-	opts->commit_argc = parse_options(argc, argv, NULL, options, usage_str,
-					PARSE_OPT_KEEP_ARGV0 |
-					PARSE_OPT_KEEP_UNKNOWN);
+	argc = parse_options(argc, argv, NULL, options, usage_str,
+			PARSE_OPT_KEEP_ARGV0 |
+			PARSE_OPT_KEEP_UNKNOWN);
 
 	/* Check for incompatible subcommands */
 	verify_opt_mutually_compatible(me,
@@ -198,9 +199,6 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 				NULL);
 	}
 
-	else if (opts->commit_argc < 2)
-		usage_with_options(usage_str, options);
-
 	if (opts->allow_ff)
 		verify_opt_compatible(me, "--ff",
 				"--signoff", opts->signoff,
@@ -208,7 +206,20 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 				"-x", opts->record_origin,
 				"--edit", opts->edit,
 				NULL);
-	opts->commit_argv = argv;
+
+	if (opts->subcommand == REPLAY_NONE) {
+		opts->revs = xmalloc(sizeof(*opts->revs));
+		init_revisions(opts->revs, NULL);
+		opts->revs->no_walk = 1;
+		if (argc < 2)
+			usage_with_options(usage_str, options);
+		argc = setup_revisions(argc, argv, opts->revs, NULL);
+	} else
+		opts->revs = NULL;
+
+	/* Forbid stray command-line arguments */
+	if (argc > 1)
+		usage_with_options(usage_str, options);
 }
 
 struct commit_message {
@@ -614,23 +625,15 @@ static int do_pick_commit(struct commit *commit, enum replay_action action,
 	return res;
 }
 
-static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)
+static void prepare_revs(struct replay_opts *opts)
 {
-	int argc;
-
-	init_revisions(revs, NULL);
-	revs->no_walk = 1;
 	if (opts->action != REPLAY_REVERT)
-		revs->reverse = 1;
+		opts->revs->reverse ^= 1;
 
-	argc = setup_revisions(opts->commit_argc, opts->commit_argv, revs, NULL);
-	if (argc > 1)
-		usage(*revert_or_cherry_pick_usage(opts));
-
-	if (prepare_revision_walk(revs))
+	if (prepare_revision_walk(opts->revs))
 		die(_("revision walk setup failed"));
 
-	if (!revs->commits)
+	if (!opts->revs->commits)
 		die(_("empty commit set passed"));
 }
 
@@ -818,14 +821,13 @@ static void read_populate_opts(struct replay_opts **opts_ptr)
 static void walk_revs_populate_todo(struct replay_insn_list **todo_list,
 				struct replay_opts *opts)
 {
-	struct rev_info revs;
 	struct commit *commit;
 	struct replay_insn_list **next;
 
-	prepare_revs(&revs, opts);
+	prepare_revs(opts);
 
 	next = todo_list;
-	while ((commit = get_revision(&revs)))
+	while ((commit = get_revision(opts->revs)))
 		next = replay_insn_list_append(opts->action, commit, next);
 }
 
@@ -949,6 +951,9 @@ static int pick_revisions(struct replay_opts *opts)
 	struct replay_insn_list *todo_list = NULL;
 	unsigned char sha1[20];
 
+	if (opts->subcommand == REPLAY_NONE)
+		assert(opts->revs);
+
 	read_and_refresh_cache(opts);
 
 	/*

From 75ba64e34129d49a79fe26a2599003892b0044e2 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2251/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index fecf0d0776..66c289803c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 0caacc73473d7513441e41a9f1430c76cf4ac7e6 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2252/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5a841da6d4..fd0afc76bc 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -155,6 +155,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index d07554c884..5fbed38637 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 5e807b9b0b..1e7771ce38 100644
--- a/cache.h
+++ b/cache.h
@@ -603,6 +603,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index efdc703257..fc7f424483 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 66c289803c..0f776c872a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -324,6 +321,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index edf9914df6..a97d0d41c6 100644
--- a/config.c
+++ b/config.c
@@ -665,6 +665,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 2c41d7d6cb..4cc125d2af 100644
--- a/environment.c
+++ b/environment.c
@@ -62,6 +62,7 @@ int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 5ef8ff76f6..1adbb55f33 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -575,4 +575,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 1f8977c0c23487b8ea64678448e7f8607ad6a54e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2253/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index fc7f424483..3d7ce02e85 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 6b76c71a7b2c72b83097b058929403777b8647e8 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2254/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 343137c18669b8e5d3dbb88186ce5b4c82ab31e1 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2255/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index f8971603f7..7d16b08ae3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1270,9 +1270,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2080,7 +2077,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2092,12 +2089,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2118,18 +2122,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2150,20 +2151,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From c72f009b9b7c223b49900a39f0e2a7a46140e833 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2256/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 7d16b08ae3..94130179b7 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 68ad44fc5767cd480e9e3e1fe5fabf021c4c74a5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2257/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 4cde0c493b..6b18e34726 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9480,7 +9480,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 4e22b11b43dc1e6c85b6f3caa26356d430b2e286 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2258/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 1a7a86dec53cbb99a1686be82f6c347d0ed5c0d6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2259/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 708f5bd4cbaf14613848fd5685d3992cb267ecb4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2260/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index fd0afc76bc..5fbefef621 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1662,6 +1662,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 261b610d24..47d465f9b2 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -87,7 +89,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -391,6 +398,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -422,6 +467,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -450,6 +502,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 08caba01edeb7be8322de9f08691a85d0af405df Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2261/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d491db92c9..d1f09be986 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From c37c9c07b3ccfa5e775b1311409931401e254015 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2262/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d1f09be986..fd283e2625 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From b2c5f24557bd549b9d7f4e2dd3a096fb81ffd829 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2263/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 0315ad76f8..fc2fb38117 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 3d7ce02e85..68d5c694bd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 0f776c872a..f81f326272 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -355,3 +355,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index a97d0d41c6..8c61ad3b8c 100644
--- a/config.c
+++ b/config.c
@@ -872,7 +872,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK)) {
diff --git a/git-compat-util.h b/git-compat-util.h
index 1adbb55f33..aec3f843eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -579,4 +579,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 639a42cf42326f2dccff21ebf4d132252421a2da Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2264/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From 48ead6e3303d0a0c9a571fd7d35e7a5e0260a40e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2265/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 9042432e23..3ed18a1886 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -557,7 +557,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -726,7 +727,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -802,7 +804,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -826,7 +828,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From a02da9624c95c264576ac2819eb1087de811ad16 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2266/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index bdd9513b84..eadb24c867 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 943450f07b77db43a0ca17d583cba3d04c5acd29 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2267/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 1e7771ce38..2b9c275c02 100644
--- a/cache.h
+++ b/cache.h
@@ -774,7 +774,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 68d5c694bd..e707f68b44 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index f81f326272..9b3eebdeb9 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -315,6 +315,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index aec3f843eb..8c9d4ed1e5 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 1d4ff04b22675da569bfb2a0e61faa27d4c7a102 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2268/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index fc2fb38117..ab0602458a 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From eb7484b56d83c1e4dead42199f9c176c68cb923b Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2269/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e707f68b44..e8c8bd5513 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From dab21c6116cebf20639edee142f55050318e705d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2270/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 94130179b7..6b72b9ef9b 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 4113cbc4c1e9f6f9bfcbe9cee5c95f64de41c405 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2271/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6b18e34726..2a92e20f06 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -369,7 +369,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9480,18 +9480,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9502,6 +9491,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 405a78ca92019dfba285bc8238ea6e26cd01d1c4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2272/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index e8c8bd5513..8cb35b693f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 6ecd89f2a6bbc7efc58ca9389aef4e3c22c32c95 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2273/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9b3eebdeb9..4b3883f39e 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -296,9 +296,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From b8da5daa8ff3de586a0041ba1d3a88ace85a3844 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2274/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From edb784e968e15842025e4304c9a3bf50daabd730 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2275/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 5da5d3337990e3b8ae743186d00e094b4df6bc40 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2276/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index 142ba51427..a8e7a40adc 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -588,7 +588,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From dd4ee9476a5959c3122133f74b18d051e537dc6a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2277/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 4f0c3bd90c..f12ba0bb15 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,6 +4274,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From fd55df23b75d34f0bda26406c5cd037c5fbfb4c2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2278/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f12ba0bb15..e23052209e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4289,7 +4289,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 65410a3e3348229c4f74cbc21901386ed58deb2a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2279/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index a4bc770e2d..a588895fcb 100644
--- a/http.c
+++ b/http.c
@@ -3,6 +3,7 @@
 #include "sideband.h"
 #include "run-command.h"
 #include "url.h"
+#include "exec_cmd.h"
 
 int data_received;
 int active_requests;
@@ -160,6 +161,18 @@ static char *git_getpass_with_description(const char *what, const char *desc)
 	return xstrdup(r);
 }
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -167,17 +180,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 2d3b42d27402a8f5610bce3d9f328cd1e2d51d78 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2280/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index c59b0c98fe..68fd050e94 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From 5bb2f1d516ae1a112b06c4ce669e17a01e94b7f5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2281/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 47d465f9b2..0e4f6ea365 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -401,7 +401,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 2867cc6de6a8b9d968598f76bf926cf6aec28190 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2282/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 7d0779f6cf..28015b12eb 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "dir.h"
 #include "thread-utils.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -187,6 +188,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_checkattr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -197,6 +214,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -514,6 +534,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -979,6 +1002,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From dfac56e3f1a067c9ac3fc5081cb893e71fdd71cf Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2283/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index bfbad086a2..cb26996f60 100644
--- a/Makefile
+++ b/Makefile
@@ -274,7 +274,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From c1bacfff2ce0957fab2dd444995ba64ee0954187 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2284/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8cb35b693f..2106ce5f78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From fb1e0763ebe78cd831a48bce9baeff76d622e2c3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2285/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index cb26996f60..06c9289e0a 100644
--- a/Makefile
+++ b/Makefile
@@ -1943,7 +1943,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -1983,6 +1983,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 9fb40fb1dfc665daf92e63a69e9e75f21a290366 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2286/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 63849836c8..2ef2ec912e 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 144890f13247d1df2c920f53a8b40e3403311ce8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2287/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 28015b12eb..fe2b5cd2d2 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1067,6 +1067,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From 5bc00c6e5a67874b41a42a2ed4ee7d3db3dada2e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2288/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index fe2b5cd2d2..75e04c903e 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1067,7 +1067,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From 83a44befc6f7fb05e52e35b5a711b84058aed65b Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2289/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 47f690fa0e87e891d3bbb9a0c060fb7012bf7223 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2290/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2106ce5f78..bf9e01fb1a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 99cffa86221e01efd772c6aaab63581b48dbfa52 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2291/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 9699336e4f70e02488f3aa9ab365ac21e49d9773 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2292/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From 601757865b3ee29cf65aeee6690847685ed7ec86 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2293/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2294/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93635..73f41482a8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2295/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 578c6a430e4e3d0ffb587e7f666d658e695cd3ea Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2296/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2297/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 4b3883f39e..0492b9c30f 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 5e7d9b77e827bd6fab225f1fc1d9a381fd8ea289 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2298/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 06c9289e0a..5395451ce7 100644
--- a/Makefile
+++ b/Makefile
@@ -1125,6 +1125,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1216,6 +1217,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From e0922cb297cd85bf76a36fa020e91b288439d0eb Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2299/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 32317325662e26d8521039a8427bd8f4db4566fb Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2300/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From b4b496762989197539221be828af78cd2623c01e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2301/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 533317bb5ba629b832562b5f11165db9f404e73f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2302/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From c1d2cbf82f5c8bae24f42edb03bfa56dc5e7a03f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2303/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bf9e01fb1a..87c8a2c0e1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 4fd2004c744f3858bb97155db9031d84049e130f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2304/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 87c8a2c0e1..509103b676 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 0492b9c30f..c5d9a79303 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 1d353909f877f538092bb542fd536945bc4a9226 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2305/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 509103b676..370cf8885c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 1b508605949757240f71b6c95b17fdddbbcfee87 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2306/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e23052209e..305a5834e5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6468,7 +6468,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6516,6 +6528,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 6f04caacfb885ee289a9f5b9b65d8f4d8884403b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2307/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 305a5834e5..de07d2d566 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,7 +4274,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 7b27d578b7b48cc0e55f476c24712f81846f8b9b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2308/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index de07d2d566..f1ebf7edf1 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6581,7 +6581,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 62b5cdfa61812e387e1f2a47bd3a357bb3d3a90f Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2309/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 370cf8885c..9aba372fa5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 493fded61a28b1a451d24915767a54f43e49d4c2 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2310/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index c5d9a79303..3d99c03b71 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 7f782ae0ae62101b83a9e1993a99466e2223b896 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Oct 2011 15:17:31 -0500
Subject: [PATCH 2311/3720] fixup! grep -I: do not bother to read known-binary
 files

---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 75e04c903e..92eeadad4c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -198,7 +198,7 @@ static int skip_binary(struct grep_opt *opt, const char *filename)
 			attr_text = git_attr("text");
 		memset(&check, 0, sizeof(check));
 		check.attr = attr_text;
-		return !git_checkattr(filename, 1, &check) &&
+		return !git_check_attr(filename, 1, &check) &&
 				ATTR_FALSE(check.value);
 	}
 	return 0;

From 018888f7f2b796941719842295608e56198731d4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2312/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index e1da468766..f440fcd23c 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 9868a0bfb4..484ff0905e 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 dry_run=
 while :
@@ -105,7 +106,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -270,7 +276,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From 46bf54011d51b5ccab827fc82568b1898faaf19f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2313/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5fbefef621..da824c92ec 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -684,6 +684,7 @@ branch..rebase::
 	When true, rebase the branch  on top of the fetched branch,
 	instead of merging the default branch from the default remote when
 	"git pull" is run.
+	When the value is `interactive`, the rebase is run in interactive mode.
 	*NOTE*: this is a possibly dangerous operation; do *not* use
 	it unless you understand the implications (see linkgit:git-rebase[1]
 	for details).
diff --git a/git-pull.sh b/git-pull.sh
index 484ff0905e..ffdc5eff98 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 dry_run=
 while :
 do

From 833a7bb84471b900097a9cd44424d9dbfec0a5bf Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 25 Oct 2011 12:06:21 -0500
Subject: [PATCH 2314/3720] git grep: be careful to use mutices only when they
 are initialized

Rather nasty things happen when a mutex is not initialized but locked
nevertheless. Now, when we're not running in a threaded manner, the mutex
is not initialized, which is correct. But then we went and used the mutex
anyway, which -- at least on Windows -- leads to a hard crash (ordinarily
it would be called a segmentation fault, but in Windows speak it is an
access violation).

This problem was identified by our faithful tests when run in the msysGit
environment.

To avoid having to wrap the line due to the 80 column limit, we use
the name "WHEN_THREADED" instead of "IF_USE_THREADS" because it is one
character shorter. Which is all we need in this case.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 92eeadad4c..e94c5fecd6 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -78,10 +78,11 @@ static pthread_mutex_t grep_mutex;
 /* Used to serialize calls to read_sha1_file. */
 static pthread_mutex_t read_sha1_mutex;
 
-#define grep_lock() pthread_mutex_lock(&grep_mutex)
-#define grep_unlock() pthread_mutex_unlock(&grep_mutex)
-#define read_sha1_lock() pthread_mutex_lock(&read_sha1_mutex)
-#define read_sha1_unlock() pthread_mutex_unlock(&read_sha1_mutex)
+#define WHEN_THREADED(x) do { if (use_threads) (x); } while (0)
+#define grep_lock() WHEN_THREADED(pthread_mutex_lock(&grep_mutex))
+#define grep_unlock() WHEN_THREADED(pthread_mutex_unlock(&grep_mutex))
+#define read_sha1_lock() WHEN_THREADED(pthread_mutex_lock(&read_sha1_mutex))
+#define read_sha1_unlock() WHEN_THREADED(pthread_mutex_unlock(&read_sha1_mutex))
 
 /* Signalled when a new work_item is added to todo. */
 static pthread_cond_t cond_add;

From f5ca42034e77c53c62312a7e341249fda84e682e Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2315/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index fecf0d0776..66c289803c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 09bbbb4dc4e2a730325d0753066d8b7b2196362d Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2316/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5a841da6d4..fd0afc76bc 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -155,6 +155,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index d07554c884..5fbed38637 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 5e807b9b0b..1e7771ce38 100644
--- a/cache.h
+++ b/cache.h
@@ -603,6 +603,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index efdc703257..fc7f424483 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 66c289803c..0f776c872a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -324,6 +321,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index edf9914df6..a97d0d41c6 100644
--- a/config.c
+++ b/config.c
@@ -665,6 +665,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 2c41d7d6cb..4cc125d2af 100644
--- a/environment.c
+++ b/environment.c
@@ -62,6 +62,7 @@ int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 5ef8ff76f6..1adbb55f33 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -575,4 +575,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From fc9c5095cee43ad1b7523fef047e4294464bfd5a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2317/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index fc7f424483..3d7ce02e85 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 18c4bffb73c9740f5c94698c16ac0d85e95904a2 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2318/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 7d183dcc344be6d78793253993e6240b95d8e9c1 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2319/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index f8971603f7..7d16b08ae3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1270,9 +1270,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2080,7 +2077,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2092,12 +2089,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2118,18 +2122,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2150,20 +2151,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From c02ced3f45bd68309599b518ccac79ed8f6c5558 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2320/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 7d16b08ae3..94130179b7 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 468bf6405079bad5af122a4134689f6742beb00a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2321/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 4cde0c493b..6b18e34726 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9480,7 +9480,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From f22c3edc54704736f53bcb9228fa4ca717f3e24d Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2322/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 278593d94546526dfec10f32096f55e3b7f8ecad Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2323/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 51208d1871088ff55a7aaddf09583fbd5f1c40c6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2324/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index fd0afc76bc..5fbefef621 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1662,6 +1662,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 261b610d24..47d465f9b2 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -87,7 +89,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -391,6 +398,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -422,6 +467,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -450,6 +502,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From b43f2999d531b0ba2155bee35dd3f63aa237bcf1 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2325/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d491db92c9..d1f09be986 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 228c42f69c1018747eb8be07194d12b41e24c75c Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2326/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d1f09be986..fd283e2625 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From fca4a4a8550f7172738f523fda114aa016fedb1a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2327/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 0315ad76f8..fc2fb38117 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 3d7ce02e85..68d5c694bd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 0f776c872a..f81f326272 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -355,3 +355,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index a97d0d41c6..8c61ad3b8c 100644
--- a/config.c
+++ b/config.c
@@ -872,7 +872,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK)) {
diff --git a/git-compat-util.h b/git-compat-util.h
index 1adbb55f33..aec3f843eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -579,4 +579,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 08642c0961dc46e14e14096a78e22fd105c4b6a4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2328/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From c9146066c4d7f226cabd97d82aa82fb76e83268f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2329/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 9042432e23..3ed18a1886 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -557,7 +557,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -726,7 +727,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -802,7 +804,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -826,7 +828,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From d68f3866e0e6235a2a45aea1a20a69ee191e85e7 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2330/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index bdd9513b84..eadb24c867 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 8f74bb90f1264d1f9b9b0d131ee236af6923abec Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2331/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 1e7771ce38..2b9c275c02 100644
--- a/cache.h
+++ b/cache.h
@@ -774,7 +774,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 68d5c694bd..e707f68b44 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index f81f326272..9b3eebdeb9 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -315,6 +315,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index aec3f843eb..8c9d4ed1e5 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 8566042646f56f03da5fdf9696037dbeda8d8e05 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2332/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index fc2fb38117..ab0602458a 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From bb6b09c47e97405fc09283c5abcdb9f58c4528c8 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2333/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e707f68b44..e8c8bd5513 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From b8a0a90f66e8d942eaf5daa524cc154c9bd3c6cb Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2334/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 94130179b7..6b72b9ef9b 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 6a15bca6c2a50b410834a842884cc95eed4599f0 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2335/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6b18e34726..2a92e20f06 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -369,7 +369,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9480,18 +9480,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9502,6 +9491,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 0a01b7d6350eaee22890a73e3485d79372ba778b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2336/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index e8c8bd5513..8cb35b693f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From bf6c56f9831bf54adae6adc45bc22ee2e84287de Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2337/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9b3eebdeb9..4b3883f39e 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -296,9 +296,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From dbcc3f5b7c67637c8fa6ad83747846d643284ab0 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2338/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 7f40b6783eef5162f46c3c22e6c31cd49899c47c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2339/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From a195415e069d4aacfa7955323769aa0ba2e585ed Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2340/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index 142ba51427..a8e7a40adc 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -588,7 +588,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 3cb12b72ea5745500c88214094c11abb34dc3408 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2341/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 4f0c3bd90c..f12ba0bb15 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,6 +4274,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 713e3829691111fae435dda7dd53a6c3ebea8d13 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2342/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f12ba0bb15..e23052209e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4289,7 +4289,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 0ca94eac6178e2a82ea6bbedc10999f2ed9938a5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2343/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index a4bc770e2d..a588895fcb 100644
--- a/http.c
+++ b/http.c
@@ -3,6 +3,7 @@
 #include "sideband.h"
 #include "run-command.h"
 #include "url.h"
+#include "exec_cmd.h"
 
 int data_received;
 int active_requests;
@@ -160,6 +161,18 @@ static char *git_getpass_with_description(const char *what, const char *desc)
 	return xstrdup(r);
 }
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -167,17 +180,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From c82433173df68843e720f939c51b85b4a3917608 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2344/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index c59b0c98fe..68fd050e94 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From 55bc333f86f8db1de3a15fea6fec7fc84b02d687 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2345/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 47d465f9b2..0e4f6ea365 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -401,7 +401,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 745a83e9b993d89aca5d23988b6664b6739f2091 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2346/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 3d7329d78c..f56ab39a81 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "dir.h"
 #include "thread-utils.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -206,6 +207,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_checkattr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -216,6 +233,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -529,6 +549,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -994,6 +1017,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 8814e6417b0dd3d6b8aa7f38b3e6c9f2cabafb28 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2347/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index bfbad086a2..cb26996f60 100644
--- a/Makefile
+++ b/Makefile
@@ -274,7 +274,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From c2cc71ab4b2847160ed8f8510c4dba4559ad3560 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2348/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8cb35b693f..2106ce5f78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 3f1b29907254032413fa1e665bd5dac9abf45cfb Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2349/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index cb26996f60..06c9289e0a 100644
--- a/Makefile
+++ b/Makefile
@@ -1943,7 +1943,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -1983,6 +1983,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 2684e38a06681a903d26f8242865160debae0cce Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2350/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 63849836c8..2ef2ec912e 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From a3170e0ee8aaad313045bbd547ea8be3adbe781f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2351/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index f56ab39a81..7d14794408 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1082,6 +1082,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From 2921b9e78bcfe5cd9f2bd8d411a65bcaa37c3e3f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2352/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 7d14794408..ebce6a626f 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1082,7 +1082,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From 5bec3d490c9e2371ed65800bf9ca2c5687c45d29 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2353/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 65adadf7cd39826efd847f4e5a755c8128cdccd5 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2354/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2106ce5f78..bf9e01fb1a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 67c9cf7ecf540c30b3d965f247eebc5a84dec83f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2355/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 496e76e32b5e9b1a9f6602f59bae5bc42d00eb26 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2356/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From 7d267ca483b5c3da9c581368c9f9d0aab44b0e02 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2357/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2358/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93635..73f41482a8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2359/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 0677a143d6f5ad606b1929750142af1a2d24ada8 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2360/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2361/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 4b3883f39e..0492b9c30f 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From a21b5f600ff666cbdcce424a8cab926129c5c584 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2362/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 06c9289e0a..5395451ce7 100644
--- a/Makefile
+++ b/Makefile
@@ -1125,6 +1125,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1216,6 +1217,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From beddf81e5618695bf46f3d1506709e6d87aa4712 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2363/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 310db8192fdadb972009d86010c675ef77961576 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2364/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From cc40d7c6fa351065546d51498af36ba471bb800e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2365/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From b6a20b0aa4e219750782c9a993584bf5b2058a61 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2366/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 29db0c9f17c5b64fb1a0651fdab32669e0effa83 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2367/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bf9e01fb1a..87c8a2c0e1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 6bbe47b555fee1f3531107b30d06c71471c43475 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2368/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 87c8a2c0e1..509103b676 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 0492b9c30f..c5d9a79303 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 022e029412436af7725a038dd590a13670e91b39 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2369/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 509103b676..370cf8885c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From b66c16b4592bf64671da18e76760972e857f0fdd Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2370/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e23052209e..305a5834e5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6468,7 +6468,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6516,6 +6528,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 48669d05eb2e6c099ea4c7db4bfa94605434ae98 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2371/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 305a5834e5..de07d2d566 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,7 +4274,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From a683e596cb28f2c42077785e2300c115853cc102 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2372/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index de07d2d566..f1ebf7edf1 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6581,7 +6581,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 93ce6c43be2519ee8ea63d16afefcede66caf848 Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2373/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 370cf8885c..9aba372fa5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From a55e32d08a09b1e0576ef5665872f8183b19dbbf Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2374/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index c5d9a79303..3d99c03b71 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 0a20caaaee937e8e0bf61a48734c1733df5d591f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Oct 2011 15:17:31 -0500
Subject: [PATCH 2375/3720] fixup! grep -I: do not bother to read known-binary
 files

---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index ebce6a626f..028090d5d6 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -217,7 +217,7 @@ static int skip_binary(struct grep_opt *opt, const char *filename)
 			attr_text = git_attr("text");
 		memset(&check, 0, sizeof(check));
 		check.attr = attr_text;
-		return !git_checkattr(filename, 1, &check) &&
+		return !git_check_attr(filename, 1, &check) &&
 				ATTR_FALSE(check.value);
 	}
 	return 0;

From 5cf8c08ff14f25d063441f18cfeafd2b50c62dae Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2376/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index e1da468766..f440fcd23c 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 9868a0bfb4..484ff0905e 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 dry_run=
 while :
@@ -105,7 +106,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -270,7 +276,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From f941f2309e6a55b1c3f343e549c1c9a8b02236d7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2377/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5fbefef621..da824c92ec 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -684,6 +684,7 @@ branch..rebase::
 	When true, rebase the branch  on top of the fetched branch,
 	instead of merging the default branch from the default remote when
 	"git pull" is run.
+	When the value is `interactive`, the rebase is run in interactive mode.
 	*NOTE*: this is a possibly dangerous operation; do *not* use
 	it unless you understand the implications (see linkgit:git-rebase[1]
 	for details).
diff --git a/git-pull.sh b/git-pull.sh
index 484ff0905e..ffdc5eff98 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 dry_run=
 while :
 do

From 47cf74ce9c7fd28914e473fd409f50e7c621913c Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2378/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index dfb0e87263..d2034b929c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From b2badafcc1d1ae6b07668475ca55c4a8cb17bd5a Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2379/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5a841da6d4..fd0afc76bc 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -155,6 +155,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index d07554c884..5fbed38637 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index dc21e6b5ce..a1ff10ad8a 100644
--- a/cache.h
+++ b/cache.h
@@ -602,6 +602,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index efdc703257..fc7f424483 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index d2034b929c..8611989783 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -117,10 +117,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -322,6 +319,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index edf9914df6..a97d0d41c6 100644
--- a/config.c
+++ b/config.c
@@ -665,6 +665,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 2c41d7d6cb..4cc125d2af 100644
--- a/environment.c
+++ b/environment.c
@@ -62,6 +62,7 @@ int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 5ef8ff76f6..1adbb55f33 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -575,4 +575,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 82c0d3c0120ad916dac92b8ce957e22f3913d48c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2380/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index fc7f424483..3d7ce02e85 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 8b8b49c82a170d476f7e87e853c636e4e66baf5d Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2381/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 10a51ab1820ef683f6b311cdb471954ff7726ff7 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2382/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index f8971603f7..7d16b08ae3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1270,9 +1270,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2080,7 +2077,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2092,12 +2089,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2118,18 +2122,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2150,20 +2151,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From a88b8493c4bd951a879d26b7806e6db4fb8fc51d Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2383/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 7d16b08ae3..94130179b7 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 841f6164d560d36349caa747134a167116eb3063 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2384/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 4cde0c493b..6b18e34726 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9480,7 +9480,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 3956fb146ae089e690c64b2516c1160c74263c07 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2385/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 094455626eac86389477b0d348677134dd06793a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2386/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 3cdf0a1e4006080b4c2514d83db881ee1b288f2a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2387/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index fd0afc76bc..5fbefef621 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1662,6 +1662,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 261b610d24..47d465f9b2 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -87,7 +89,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -391,6 +398,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -422,6 +467,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -450,6 +502,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 42ff399a5f74ea11b1f562515b8c76e64af61d3e Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2388/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d491db92c9..d1f09be986 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 185375278029f9497cdb6720e8ba384d597000d6 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2389/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d1f09be986..fd283e2625 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 4145de0853e96cda9be20b8cf3706a74c9538235 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2390/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 0315ad76f8..fc2fb38117 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 3d7ce02e85..68d5c694bd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 8611989783..63064953da 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -353,3 +353,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index a97d0d41c6..8c61ad3b8c 100644
--- a/config.c
+++ b/config.c
@@ -872,7 +872,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK)) {
diff --git a/git-compat-util.h b/git-compat-util.h
index 1adbb55f33..aec3f843eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -579,4 +579,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From a6f5cf04e876866560d1d562cdad28942e24d707 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2391/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From afd7ac6f936c3a9c17a989ca07b5795ebb6f80ff Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2392/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 9042432e23..3ed18a1886 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -557,7 +557,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -726,7 +727,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -802,7 +804,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -826,7 +828,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From 3387e2df2248f4f5c9f0148b7e00fe1dbff70387 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2393/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index bdd9513b84..eadb24c867 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 3632e79c78a690505df4e436963406e15826203c Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2394/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index a1ff10ad8a..fdc3a5888f 100644
--- a/cache.h
+++ b/cache.h
@@ -773,7 +773,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 68d5c694bd..e707f68b44 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 63064953da..ffc0d1d5c2 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -313,6 +313,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index aec3f843eb..8c9d4ed1e5 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 3139af0557256998d25a98154c0937c29281f3b7 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2395/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index fc2fb38117..ab0602458a 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From 67f4d19d9d9d8059a520216eba72a115ba6cf6c0 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2396/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e707f68b44..e8c8bd5513 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From dc0994e9d76ce13c40e8dc9316dff709c2c35bc0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2397/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 94130179b7..6b72b9ef9b 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 40289cd71a0f7f70e6549b44286201eca5f3fd55 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2398/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6b18e34726..2a92e20f06 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -369,7 +369,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9480,18 +9480,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9502,6 +9491,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 977f2147b50da0c9ecb65a3e85ae22a7c0363643 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2399/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index e8c8bd5513..8cb35b693f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 4278d131a432a403c947c321aac90ff2c432825f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2400/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index ffc0d1d5c2..9464a1391d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -294,9 +294,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 78e350f0e9cfd506b735f7bb26a62a9699b90a3c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2401/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 73f3692a5d2e0104e32683ce89260ebc929f8a54 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2402/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 62f41271b34272831533317d1073b8dcdc1f4618 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2403/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index 142ba51427..a8e7a40adc 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -588,7 +588,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 3488c428da4c4f0a3896748b76fda5094793ac3b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2404/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 4f0c3bd90c..f12ba0bb15 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,6 +4274,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From abb969ff52c82278067177c5283c27abdd097d69 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2405/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f12ba0bb15..e23052209e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4289,7 +4289,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From aa7d9f92c0810ca964298cab924a533b3ec58147 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2406/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index a4bc770e2d..a588895fcb 100644
--- a/http.c
+++ b/http.c
@@ -3,6 +3,7 @@
 #include "sideband.h"
 #include "run-command.h"
 #include "url.h"
+#include "exec_cmd.h"
 
 int data_received;
 int active_requests;
@@ -160,6 +161,18 @@ static char *git_getpass_with_description(const char *what, const char *desc)
 	return xstrdup(r);
 }
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -167,17 +180,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 8117c57d9098f938b1dfd517f0d35c4be498390e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2407/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index c59b0c98fe..68fd050e94 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From 5648129c661f99fddb91201e34a87f65891c98f7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2408/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 47d465f9b2..0e4f6ea365 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -401,7 +401,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From a48d98963d665aed3cf17a24000d18983b74b310 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2409/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 988ea1d332..133c4583b7 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "dir.h"
 #include "thread-utils.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -206,6 +207,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -216,6 +233,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -529,6 +549,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -995,6 +1018,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From cde6d250583454358fe60caee1d6d3e4a8d45c09 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2410/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3b83e46548..9685fb7bb6 100644
--- a/Makefile
+++ b/Makefile
@@ -274,7 +274,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From 61d3c90a3f904818f34396daf13ae0d8d024c1d8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2411/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8cb35b693f..2106ce5f78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 9291c4e7a8185ea7ffff999a7158066137f679d3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2412/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 9685fb7bb6..6806b99aff 100644
--- a/Makefile
+++ b/Makefile
@@ -1945,7 +1945,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -1985,6 +1985,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From b021d424c47eb087e019a4b9ba74a58f11a00b31 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2413/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 63849836c8..2ef2ec912e 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 52a79cc107ee96528a6b4ee371b3de49dbb555e0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2414/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 133c4583b7..63b00f8fab 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1083,6 +1083,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From a1de966b3e16d34146cd029dc7dd6adbaf728731 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2415/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 63b00f8fab..b18491bc8c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1083,7 +1083,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From cb89d5c9f5293428245ce6ea4c3df409d617ac01 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2416/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From da4af3a2566570fbe65879666ef2ebe645fccb19 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2417/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2106ce5f78..bf9e01fb1a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 9d4e5942604a68c9bef55b2a2ebc8fa41de70c8a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2418/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From b5e38078fa0a3d2d737e55b3f5d63fd6b5dc360f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2419/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From 81375971b05a2d6d352140209afd643716411821 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2420/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2421/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93635..73f41482a8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2422/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 9d9a626b8c05a7b714ddcc6f5232fcc0814b3010 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2423/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2424/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9464a1391d..bb6cd9ab7b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From a8a0a36c23bca6eb15e528c3febe85cfad63b1c4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2425/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 6806b99aff..2837e7920c 100644
--- a/Makefile
+++ b/Makefile
@@ -1126,6 +1126,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1218,6 +1219,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From fa50ef6541daa64355282c03aa840c15a47ab708 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2426/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From f9e54cde664407a534c18e3218da3c47315c8e41 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2427/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From e9da58c89c00fefc3e45014d3a0b1a09c1be6385 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2428/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 7e6b12114e81508e0ceb6d152c796515853e926b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2429/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 4afc7dcc59b5c7c8ce52bf66d8c234d3535bdab4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2430/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bf9e01fb1a..87c8a2c0e1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From a3329a070bfda256a60a6d44f8e94367e30bd9c5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2431/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 87c8a2c0e1..509103b676 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index bb6cd9ab7b..90b53015bb 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -328,22 +328,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 0823c305dce2f2dcc1cde5706aab71bf76a87627 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2432/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 509103b676..370cf8885c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From b03ff687ab611c0845b19212d9da4e6017503bea Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2433/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e23052209e..305a5834e5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6468,7 +6468,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6516,6 +6528,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 63a0330848753392386d7b24b03821e65c661560 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2434/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 305a5834e5..de07d2d566 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,7 +4274,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From a6437f42cb78e4932a6bd8a231343d0e64ac6c7a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2435/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index de07d2d566..f1ebf7edf1 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6581,7 +6581,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From f3059a34933afc89929d8b443d095187cd19c069 Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2436/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 370cf8885c..9aba372fa5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From afe6b38c8d6bc007a9b42041b0b1f5298a2d187b Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2437/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 90b53015bb..cdaa7ba476 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From fff9b51152951264f8f1c5e5222f4c6a0d873cc1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2438/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index e1da468766..f440fcd23c 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 9868a0bfb4..484ff0905e 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 dry_run=
 while :
@@ -105,7 +106,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -270,7 +276,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From 3608d4fbf90abe9be4b352ce44ae208b3bc2cccb Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2439/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5fbefef621..da824c92ec 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -684,6 +684,7 @@ branch..rebase::
 	When true, rebase the branch  on top of the fetched branch,
 	instead of merging the default branch from the default remote when
 	"git pull" is run.
+	When the value is `interactive`, the rebase is run in interactive mode.
 	*NOTE*: this is a possibly dangerous operation; do *not* use
 	it unless you understand the implications (see linkgit:git-rebase[1]
 	for details).
diff --git a/git-pull.sh b/git-pull.sh
index 484ff0905e..ffdc5eff98 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 dry_run=
 while :
 do

From bcfb74d23c13dfda1a0045eb6461ef1682143862 Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:42 +0100
Subject: [PATCH 2440/3720] Compile fix for MSVC: Do not include
 sys/resources.h

Do not include header files when compiling with MSVC that do not
exist and which are also not included when compiling with MINGW.
A direct consequence is that git can be compiled again with MSVC
because the missing "sys/resources.h" is no longer included.

Instead of current

	#ifndef mingw32 is the only one that is strange
        ... everything for systems that is not strange ...
        #else
        ... include mingw specific tweaks ...
        #endif
        #ifdef msvc is also strange
        ... include msvc specific tweaks ...
        #endif

it turns things around and says what it wants to achieve in a more direct
way, i.e.

	#if mingw32
        #include "compat/mingw.h"
	#elif msvc
        #include "compat/msvc.h"
	#else
        ... all the others ...
	#endif

which makes it look simpler.

Signed-off-by: Vincent van Ravesteijn 
Helped-by: Junio C Hamano 
Signed-off-by: Erik Faye-Lund 
---
 git-compat-util.h | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index 8c9d4ed1e5..0135dcc950 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -116,7 +116,12 @@
 #else
 #include 
 #endif
-#ifndef __MINGW32__
+#if defined(__MINGW32__)
+/* pull in Windows compatibility stuff */
+#include "compat/mingw.h"
+#elif defined(_MSC_VER)
+#include "compat/msvc.h"
+#else
 #include 
 #include 
 #include 
@@ -145,12 +150,6 @@
 #include 
 #define _ALL_SOURCE 1
 #endif
-#else 	/* __MINGW32__ */
-/* pull in Windows compatibility stuff */
-#include "compat/mingw.h"
-#endif	/* __MINGW32__ */
-#ifdef _MSC_VER
-#include "compat/msvc.h"
 #endif
 
 #ifndef NO_LIBGEN_H

From 59a6cc522f063825168b72232a9d69115380f001 Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:43 +0100
Subject: [PATCH 2441/3720] Compile fix for MSVC: Include 

This include is needed for _commit(..) which is used in mingw.h.

Signed-off-by: Vincent van Ravesteijn 
Signed-off-by: Erik Faye-Lund 
---
 compat/msvc.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/compat/msvc.h b/compat/msvc.h
index a33b01c032..aa4b56315a 100644
--- a/compat/msvc.h
+++ b/compat/msvc.h
@@ -4,6 +4,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* porting function */
 #define inline __inline

From 36fe213cc139f4f4663e23b45fa4c74332199cf1 Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:44 +0100
Subject: [PATCH 2442/3720] MSVC: Remove unneeded header stubs

These headers are no longer needed since they are no longer
unnecessarily included in git-compat-util.h.

Signed-off-by: Vincent van Ravesteijn 
Signed-off-by: Erik Faye-Lund 
---
 compat/vcbuild/include/arpa/inet.h   | 1 -
 compat/vcbuild/include/grp.h         | 1 -
 compat/vcbuild/include/inttypes.h    | 1 -
 compat/vcbuild/include/netdb.h       | 1 -
 compat/vcbuild/include/netinet/in.h  | 1 -
 compat/vcbuild/include/netinet/tcp.h | 1 -
 compat/vcbuild/include/pwd.h         | 1 -
 compat/vcbuild/include/sys/ioctl.h   | 1 -
 compat/vcbuild/include/sys/select.h  | 1 -
 compat/vcbuild/include/sys/socket.h  | 1 -
 compat/vcbuild/include/sys/wait.h    | 1 -
 compat/vcbuild/include/termios.h     | 1 -
 12 files changed, 12 deletions(-)
 delete mode 100644 compat/vcbuild/include/arpa/inet.h
 delete mode 100644 compat/vcbuild/include/grp.h
 delete mode 100644 compat/vcbuild/include/inttypes.h
 delete mode 100644 compat/vcbuild/include/netdb.h
 delete mode 100644 compat/vcbuild/include/netinet/in.h
 delete mode 100644 compat/vcbuild/include/netinet/tcp.h
 delete mode 100644 compat/vcbuild/include/pwd.h
 delete mode 100644 compat/vcbuild/include/sys/ioctl.h
 delete mode 100644 compat/vcbuild/include/sys/select.h
 delete mode 100644 compat/vcbuild/include/sys/socket.h
 delete mode 100644 compat/vcbuild/include/sys/wait.h
 delete mode 100644 compat/vcbuild/include/termios.h

diff --git a/compat/vcbuild/include/arpa/inet.h b/compat/vcbuild/include/arpa/inet.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/arpa/inet.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/grp.h b/compat/vcbuild/include/grp.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/grp.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/inttypes.h b/compat/vcbuild/include/inttypes.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/inttypes.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netdb.h b/compat/vcbuild/include/netdb.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netdb.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netinet/in.h b/compat/vcbuild/include/netinet/in.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netinet/in.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netinet/tcp.h b/compat/vcbuild/include/netinet/tcp.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netinet/tcp.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/pwd.h b/compat/vcbuild/include/pwd.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/pwd.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/ioctl.h b/compat/vcbuild/include/sys/ioctl.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/ioctl.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/select.h b/compat/vcbuild/include/sys/select.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/select.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/socket.h b/compat/vcbuild/include/sys/socket.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/socket.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/wait.h b/compat/vcbuild/include/sys/wait.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/wait.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/termios.h b/compat/vcbuild/include/termios.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/termios.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */

From e6b6048ee3838d91c2f5f3ee7d46eb623cfef8a2 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:56:21 +0100
Subject: [PATCH 2443/3720] mingw: poll.h is no longer in sys/

Earlier we moved this header file in the code but forgot to
update the Makefile that refers to it.

Signed-off-by: Junio C Hamano 
Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 2837e7920c..70edb11c55 100644
--- a/Makefile
+++ b/Makefile
@@ -518,7 +518,7 @@ LIB_H += compat/mingw.h
 LIB_H += compat/obstack.h
 LIB_H += compat/win32/pthread.h
 LIB_H += compat/win32/syslog.h
-LIB_H += compat/win32/sys/poll.h
+LIB_H += compat/win32/poll.h
 LIB_H += compat/win32/dirent.h
 LIB_H += connected.h
 LIB_H += csum-file.h

From 0cb3e1b53b08d0096385690fb308ba3f9a69cfef Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 2444/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index cdaa7ba476..ee76d6bf97 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 0135dcc950..cd289daa21 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From 762afc7f7858fb2e71f5d646fbc52cf33e4abb5a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 2445/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From 4e0fc71c6086615b66735ee8a7a5c636623d59a6 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 2446/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 70edb11c55..483ef5cfde 100644
--- a/Makefile
+++ b/Makefile
@@ -1124,6 +1124,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From f37a559247ce1bf07146608cc89765cc826d7f40 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Mon, 31 Oct 2011 14:05:45 +0000
Subject: [PATCH 2447/3720] t7511: avoid use of reserved filename on Windows.

PRN is a special filename on Windows to send data to the printer. As
this is generated during test 3 substitute an alternate prefix to avoid this.

Signed-off-by: Pat Thoyts 
---
 t/t7511-status-index.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t7511-status-index.sh b/t/t7511-status-index.sh
index bca359dc1e..b5fdc048a5 100755
--- a/t/t7511-status-index.sh
+++ b/t/t7511-status-index.sh
@@ -24,7 +24,7 @@ check() {
 
 check  1
 check  2 p
-check  3 pr
+check  3 px
 check  4 pre
 check  5 pref
 check  6 prefi

From a1c14aba55df79ef0532400e391040112142ac9e Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2448/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index dfb0e87263..d2034b929c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From a759e75ec5462a36c74eb1660ad904ca29b03326 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2449/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5a841da6d4..fd0afc76bc 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -155,6 +155,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index d07554c884..5fbed38637 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index dc21e6b5ce..a1ff10ad8a 100644
--- a/cache.h
+++ b/cache.h
@@ -602,6 +602,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index efdc703257..fc7f424483 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index d2034b929c..8611989783 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -117,10 +117,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -322,6 +319,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index edf9914df6..a97d0d41c6 100644
--- a/config.c
+++ b/config.c
@@ -665,6 +665,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 2c41d7d6cb..4cc125d2af 100644
--- a/environment.c
+++ b/environment.c
@@ -62,6 +62,7 @@ int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 5ef8ff76f6..1adbb55f33 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -575,4 +575,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 93a6ef0e0a9c15072805846637f1d08f6977b584 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2450/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index fc7f424483..3d7ce02e85 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From c05075b393ce0a015fb9757e673cf5f325f6f6d5 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2451/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 9ce13e5fbc946b0727cc6fa4c5fc0a8bdbe18bf7 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2452/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index f8971603f7..7d16b08ae3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1270,9 +1270,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2080,7 +2077,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2092,12 +2089,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2118,18 +2122,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2150,20 +2151,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From f98a60869f4c8f8bcb7216af098e2c616c259464 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2453/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 7d16b08ae3..94130179b7 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From fd4e43dd9b567d906d7e96c0f2f364e0b1f38c9d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2454/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 4cde0c493b..6b18e34726 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9480,7 +9480,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From f3d7d8f01e20be2f89ed5a8a9de25d0b11957f45 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2455/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From c725a9a2cd5a7a2f29adec4bc07ee4e08682f35a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2456/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 324412088218df7ce17ef0774ff62f6981ed2a68 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2457/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index fd0afc76bc..5fbefef621 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1662,6 +1662,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 261b610d24..47d465f9b2 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -87,7 +89,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -391,6 +398,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -422,6 +467,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -450,6 +502,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 16b9dcc36d75aed7c39d5dc2d7c3dafb8e02f0bc Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2458/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d491db92c9..d1f09be986 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 603e7f185ff423996283455f60bc359a6201c24f Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2459/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d1f09be986..fd283e2625 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 51171fc548ed6f05055fc1872d1875eda7c1b260 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2460/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 0315ad76f8..fc2fb38117 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 3d7ce02e85..68d5c694bd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 8611989783..63064953da 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -353,3 +353,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index a97d0d41c6..8c61ad3b8c 100644
--- a/config.c
+++ b/config.c
@@ -872,7 +872,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK)) {
diff --git a/git-compat-util.h b/git-compat-util.h
index 1adbb55f33..aec3f843eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -579,4 +579,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 2ff6e917da6305951c89c02d1798d8e1697c1930 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2461/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From 5956c9aebef6a6d25bc6c4d85303f3835a824bff Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2462/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 9042432e23..3ed18a1886 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -557,7 +557,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -726,7 +727,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -802,7 +804,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -826,7 +828,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From 12051e5613425efdbdd64cde1987dcc19c2f44ae Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2463/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index bdd9513b84..eadb24c867 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 016f47e7402c03ea212f3be0aacd7c5aeb843437 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2464/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index a1ff10ad8a..fdc3a5888f 100644
--- a/cache.h
+++ b/cache.h
@@ -773,7 +773,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 68d5c694bd..e707f68b44 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 63064953da..ffc0d1d5c2 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -313,6 +313,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index aec3f843eb..8c9d4ed1e5 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 7b0967d065430ea2ea2b2bc5c3390a744760bb38 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2465/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index fc2fb38117..ab0602458a 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From 1bd7b49e00739e4cfcff3248601a8013d808e0ee Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2466/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e707f68b44..e8c8bd5513 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 905a8767d85ab3087e428bcaddef80b02abac5a6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2467/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 94130179b7..6b72b9ef9b 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 0a9bbaddda59d99094d8a55b8fd68cec71eca544 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2468/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6b18e34726..2a92e20f06 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -369,7 +369,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9480,18 +9480,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9502,6 +9491,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From f93cb107fa5740585082a3491782284e5c62bc6c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2469/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index e8c8bd5513..8cb35b693f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 0d16a58577077f4185200b8b8b488513391b2ae2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2470/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index ffc0d1d5c2..9464a1391d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -294,9 +294,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 4117f569419f255dd25b4e20c6679f752c13b540 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2471/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 917200f36363ecd58cecaedaae8cfd4a0a437c5c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2472/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 54db428060115ad8ca8b36733797bcca2cbb9966 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2473/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index 142ba51427..a8e7a40adc 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -588,7 +588,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 62b255f6e9b8f1b21a9b7317b0f9f47bc9b0569a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2474/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 4f0c3bd90c..f12ba0bb15 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,6 +4274,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From adfbbb2bb2ae349ed6961134a63b7197c031e82f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2475/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f12ba0bb15..e23052209e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4289,7 +4289,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 21098cf6ef38833d16100879d62f45d2c8b827ab Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2476/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index a4bc770e2d..a588895fcb 100644
--- a/http.c
+++ b/http.c
@@ -3,6 +3,7 @@
 #include "sideband.h"
 #include "run-command.h"
 #include "url.h"
+#include "exec_cmd.h"
 
 int data_received;
 int active_requests;
@@ -160,6 +161,18 @@ static char *git_getpass_with_description(const char *what, const char *desc)
 	return xstrdup(r);
 }
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -167,17 +180,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 08293dfd3cad513a7aee5493215c83fb7b54b52e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2477/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index c59b0c98fe..68fd050e94 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From cfe6430df89d176c6050ed73d3de16a8598337d4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2478/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 47d465f9b2..0e4f6ea365 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -401,7 +401,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 3e870a0da457f26cfe69b692ba4f9113be764499 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2479/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 988ea1d332..133c4583b7 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "dir.h"
 #include "thread-utils.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -206,6 +207,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -216,6 +233,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -529,6 +549,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -995,6 +1018,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 5ff6a66e7f0df2263175a0f901a709ae4b7a9904 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2480/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 58505b07eb..fdc777d287 100644
--- a/Makefile
+++ b/Makefile
@@ -274,7 +274,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From a2cda2f3c6b1600ccb86e8e8221b0c271a165750 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2481/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8cb35b693f..2106ce5f78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 9185631d00a41ecdd61e0e7cab196fead6f4b240 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2482/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index fdc777d287..03e64695fd 100644
--- a/Makefile
+++ b/Makefile
@@ -1945,7 +1945,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -1985,6 +1985,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From ad9b06cbb99029607115ba399ccbd281bd2b331b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2483/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 63849836c8..2ef2ec912e 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 5a530133d6f1db4e09193fb97745e37a862503fd Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2484/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 133c4583b7..63b00f8fab 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1083,6 +1083,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From a3eb612f706cc4cfcd36768a203efecf5ef2d716 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2485/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 63b00f8fab..b18491bc8c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1083,7 +1083,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From 19954b2b858aaeb7feac7b2e3d3b626d24cf3995 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2486/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From d90dee0cecf7a5dcc17b0a484517ad4511873fdc Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2487/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2106ce5f78..bf9e01fb1a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From ebe00057fa02d9def2f8ccd39af5699560b591d1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2488/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 92b7d5074350fccfc28e4fcace8d789e0a872eea Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2489/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From 3ca0a67d6f3d07773bd3b32e742d2f98d870d0dc Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2490/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2491/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93635..73f41482a8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2492/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From d278064270ec150dfef3ed8e2fd30b4606e10f74 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2493/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2494/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9464a1391d..bb6cd9ab7b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 4945dccdc530f6dd7daea2735fd0913d036c6589 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2495/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 03e64695fd..70edb11c55 100644
--- a/Makefile
+++ b/Makefile
@@ -1126,6 +1126,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1218,6 +1219,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 1b76646c73da2d91a7108e2206e0cbb68f7342fe Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2496/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From d4aeefbc5d2d507e97f6663a30a3e9336fb9b31c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2497/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From da28481a359613e5545aa6ee4fc4c5d5754584dc Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2498/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 48ba8e74d133b19250f8d9b953781e6e0ac30933 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2499/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From f2a4c12c3893362a93015cb9984b304cef8298c5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2500/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bf9e01fb1a..87c8a2c0e1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From b52a68830da10fd013f7d639601e87010229cdf7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2501/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 87c8a2c0e1..509103b676 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index bb6cd9ab7b..90b53015bb 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -328,22 +328,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 15205be18f041b4af2ed47a6afc0c64350431131 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2502/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 509103b676..370cf8885c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 9e9e5f808ebdbf63f6880b080fce61b24423e609 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2503/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e23052209e..305a5834e5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6468,7 +6468,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6516,6 +6528,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From dd57f97e87b8aa48a66b70fe02a282a60a1479d8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2504/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 305a5834e5..de07d2d566 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,7 +4274,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From c3f7c8fc905b581ef0003e24a69ed8b41e498d80 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2505/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index de07d2d566..f1ebf7edf1 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6581,7 +6581,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From be51338063d54e4aac110bbb59c7e16d49cd6f90 Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2506/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 370cf8885c..9aba372fa5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 22621b1aa2134c40ae9dca0fbc08a9fa1526f95a Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2507/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 90b53015bb..cdaa7ba476 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 65f4e87aaaffc198dc0237289242dca09a34f8b3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2508/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index e1da468766..f440fcd23c 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 9868a0bfb4..484ff0905e 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 dry_run=
 while :
@@ -105,7 +106,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -270,7 +276,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From 970192de1f3b548935583520152faa94d779d532 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2509/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5fbefef621..da824c92ec 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -684,6 +684,7 @@ branch..rebase::
 	When true, rebase the branch  on top of the fetched branch,
 	instead of merging the default branch from the default remote when
 	"git pull" is run.
+	When the value is `interactive`, the rebase is run in interactive mode.
 	*NOTE*: this is a possibly dangerous operation; do *not* use
 	it unless you understand the implications (see linkgit:git-rebase[1]
 	for details).
diff --git a/git-pull.sh b/git-pull.sh
index 484ff0905e..ffdc5eff98 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 dry_run=
 while :
 do

From 934e193989a0ab6ddea6af6a5e418d8721d9212b Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:42 +0100
Subject: [PATCH 2510/3720] Compile fix for MSVC: Do not include
 sys/resources.h

Do not include header files when compiling with MSVC that do not
exist and which are also not included when compiling with MINGW.
A direct consequence is that git can be compiled again with MSVC
because the missing "sys/resources.h" is no longer included.

Instead of current

	#ifndef mingw32 is the only one that is strange
        ... everything for systems that is not strange ...
        #else
        ... include mingw specific tweaks ...
        #endif
        #ifdef msvc is also strange
        ... include msvc specific tweaks ...
        #endif

it turns things around and says what it wants to achieve in a more direct
way, i.e.

	#if mingw32
        #include "compat/mingw.h"
	#elif msvc
        #include "compat/msvc.h"
	#else
        ... all the others ...
	#endif

which makes it look simpler.

Signed-off-by: Vincent van Ravesteijn 
Helped-by: Junio C Hamano 
Signed-off-by: Erik Faye-Lund 
---
 git-compat-util.h | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index 8c9d4ed1e5..0135dcc950 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -116,7 +116,12 @@
 #else
 #include 
 #endif
-#ifndef __MINGW32__
+#if defined(__MINGW32__)
+/* pull in Windows compatibility stuff */
+#include "compat/mingw.h"
+#elif defined(_MSC_VER)
+#include "compat/msvc.h"
+#else
 #include 
 #include 
 #include 
@@ -145,12 +150,6 @@
 #include 
 #define _ALL_SOURCE 1
 #endif
-#else 	/* __MINGW32__ */
-/* pull in Windows compatibility stuff */
-#include "compat/mingw.h"
-#endif	/* __MINGW32__ */
-#ifdef _MSC_VER
-#include "compat/msvc.h"
 #endif
 
 #ifndef NO_LIBGEN_H

From b717602fa90e79efd4afc85f54df4a5acac782ce Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:43 +0100
Subject: [PATCH 2511/3720] Compile fix for MSVC: Include 

This include is needed for _commit(..) which is used in mingw.h.

Signed-off-by: Vincent van Ravesteijn 
Signed-off-by: Erik Faye-Lund 
---
 compat/msvc.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/compat/msvc.h b/compat/msvc.h
index a33b01c032..aa4b56315a 100644
--- a/compat/msvc.h
+++ b/compat/msvc.h
@@ -4,6 +4,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* porting function */
 #define inline __inline

From 323bf8effb18ffd7133469e61e1479110a907292 Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:44 +0100
Subject: [PATCH 2512/3720] MSVC: Remove unneeded header stubs

These headers are no longer needed since they are no longer
unnecessarily included in git-compat-util.h.

Signed-off-by: Vincent van Ravesteijn 
Signed-off-by: Erik Faye-Lund 
---
 compat/vcbuild/include/arpa/inet.h   | 1 -
 compat/vcbuild/include/grp.h         | 1 -
 compat/vcbuild/include/inttypes.h    | 1 -
 compat/vcbuild/include/netdb.h       | 1 -
 compat/vcbuild/include/netinet/in.h  | 1 -
 compat/vcbuild/include/netinet/tcp.h | 1 -
 compat/vcbuild/include/pwd.h         | 1 -
 compat/vcbuild/include/sys/ioctl.h   | 1 -
 compat/vcbuild/include/sys/select.h  | 1 -
 compat/vcbuild/include/sys/socket.h  | 1 -
 compat/vcbuild/include/sys/wait.h    | 1 -
 compat/vcbuild/include/termios.h     | 1 -
 12 files changed, 12 deletions(-)
 delete mode 100644 compat/vcbuild/include/arpa/inet.h
 delete mode 100644 compat/vcbuild/include/grp.h
 delete mode 100644 compat/vcbuild/include/inttypes.h
 delete mode 100644 compat/vcbuild/include/netdb.h
 delete mode 100644 compat/vcbuild/include/netinet/in.h
 delete mode 100644 compat/vcbuild/include/netinet/tcp.h
 delete mode 100644 compat/vcbuild/include/pwd.h
 delete mode 100644 compat/vcbuild/include/sys/ioctl.h
 delete mode 100644 compat/vcbuild/include/sys/select.h
 delete mode 100644 compat/vcbuild/include/sys/socket.h
 delete mode 100644 compat/vcbuild/include/sys/wait.h
 delete mode 100644 compat/vcbuild/include/termios.h

diff --git a/compat/vcbuild/include/arpa/inet.h b/compat/vcbuild/include/arpa/inet.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/arpa/inet.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/grp.h b/compat/vcbuild/include/grp.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/grp.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/inttypes.h b/compat/vcbuild/include/inttypes.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/inttypes.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netdb.h b/compat/vcbuild/include/netdb.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netdb.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netinet/in.h b/compat/vcbuild/include/netinet/in.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netinet/in.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netinet/tcp.h b/compat/vcbuild/include/netinet/tcp.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netinet/tcp.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/pwd.h b/compat/vcbuild/include/pwd.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/pwd.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/ioctl.h b/compat/vcbuild/include/sys/ioctl.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/ioctl.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/select.h b/compat/vcbuild/include/sys/select.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/select.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/socket.h b/compat/vcbuild/include/sys/socket.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/socket.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/wait.h b/compat/vcbuild/include/sys/wait.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/wait.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/termios.h b/compat/vcbuild/include/termios.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/termios.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */

From 26469e3967ac3f31c756da3821bd657c380c22ab Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 2513/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index cdaa7ba476..ee76d6bf97 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 0135dcc950..cd289daa21 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From a894c9a895f471b29c94429212ba6cf1bf895073 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 2514/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From ef4f9501362bf62817934cbaa65e11212afda697 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 2515/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 70edb11c55..483ef5cfde 100644
--- a/Makefile
+++ b/Makefile
@@ -1124,6 +1124,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From 73afc4622baf992389047b1abcd8267da3545c1d Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2516/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index dfb0e87263..d2034b929c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From c40046bd0f747a831ecfc4862efcda047b8156e7 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2517/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5a841da6d4..fd0afc76bc 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -155,6 +155,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index d07554c884..5fbed38637 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index dc21e6b5ce..a1ff10ad8a 100644
--- a/cache.h
+++ b/cache.h
@@ -602,6 +602,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index efdc703257..fc7f424483 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index d2034b929c..8611989783 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -117,10 +117,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -322,6 +319,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index edf9914df6..a97d0d41c6 100644
--- a/config.c
+++ b/config.c
@@ -665,6 +665,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 2c41d7d6cb..4cc125d2af 100644
--- a/environment.c
+++ b/environment.c
@@ -62,6 +62,7 @@ int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 5ef8ff76f6..1adbb55f33 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -575,4 +575,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From d24ec016b3ea7b5ac9da8cf012898818fe911770 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2518/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index fc7f424483..3d7ce02e85 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 40e6ef79914f39e74025ce853850dd1bd166faca Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2519/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 9e89381e1a66c439fdb1e6d7e82b1e16ba617ae3 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2520/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index f8971603f7..7d16b08ae3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1270,9 +1270,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2080,7 +2077,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2092,12 +2089,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2118,18 +2122,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2150,20 +2151,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 59e0e6033d204c4230baab1c3f46fc4d513aaac7 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2521/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 7d16b08ae3..94130179b7 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From f9445e4ae5172c3d51223555be3a508f8ab7f790 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2522/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 4cde0c493b..6b18e34726 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9480,7 +9480,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From b81e593c7da42d8383e47bf4ae45cee91959c42d Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2523/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 2afff367936858230081930ae228ffe97355472c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2524/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 6274596feebbfe99a0d12288bcf72101676ae14f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2525/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index fd0afc76bc..5fbefef621 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1662,6 +1662,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 7ec68a1e80..6099521224 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -87,7 +89,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -391,6 +398,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -422,6 +467,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -450,6 +502,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 32eefc4f13288fcd15681b3f58cb0570b24cab77 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2526/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d491db92c9..d1f09be986 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From ede54b171ec1d8ed0a52d5d66256128b3f49b1a2 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2527/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d1f09be986..fd283e2625 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 3649391f543f9deb9f8401f30badbc97ee655efc Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2528/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 0315ad76f8..fc2fb38117 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 3d7ce02e85..68d5c694bd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 8611989783..63064953da 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -353,3 +353,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index a97d0d41c6..8c61ad3b8c 100644
--- a/config.c
+++ b/config.c
@@ -872,7 +872,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK)) {
diff --git a/git-compat-util.h b/git-compat-util.h
index 1adbb55f33..aec3f843eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -579,4 +579,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From d23ce6fa579111c1e18cb18e856d3e3846e4ddc0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2529/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From fef92f8ff5824ecbc4d65bd33b6daeca9452c400 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2530/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 9042432e23..3ed18a1886 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -557,7 +557,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -726,7 +727,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -802,7 +804,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -826,7 +828,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From 3d08379e7a806db666c63421c04ad0dc680cee0e Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2531/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index bdd9513b84..eadb24c867 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 1f3a4f80cb2453d14994bb5f8483c06ad8935e2d Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2532/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index a1ff10ad8a..fdc3a5888f 100644
--- a/cache.h
+++ b/cache.h
@@ -773,7 +773,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 68d5c694bd..e707f68b44 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 63064953da..ffc0d1d5c2 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -313,6 +313,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index aec3f843eb..8c9d4ed1e5 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 1c072a62113e2e239da96c4df89718e242bc1185 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2533/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index fc2fb38117..ab0602458a 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From 7602e52bfc6f1fee3611ec53739aba174085a865 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2534/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e707f68b44..e8c8bd5513 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From d0a4bbe3f304ec6dc7229c99c417684a7063365a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2535/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 94130179b7..6b72b9ef9b 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 3bef2667032e1cf6c8e90321befc0ec4d4387612 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2536/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6b18e34726..2a92e20f06 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -369,7 +369,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9480,18 +9480,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9502,6 +9491,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From e3356ac2e579e9868e4e0b1015fcf6ae75f6ea6a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2537/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index e8c8bd5513..8cb35b693f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 9b505ab138fc30ff8f5fe6425b414e5d1eaeb8fb Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2538/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index ffc0d1d5c2..9464a1391d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -294,9 +294,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From bfcdc94ec07542401f33d6e4d88fe59ef89fe9a0 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2539/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 6f86c3ee55c972ebb4b3eb51e807a38aa85d4abe Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2540/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From feab00399b2138c6723e6256d8a9c8b6aa27987e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2541/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index 142ba51427..a8e7a40adc 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -588,7 +588,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From ff19df47d991f4a0b407536be197e7882ddb2522 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2542/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 4f0c3bd90c..f12ba0bb15 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,6 +4274,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 621a9581ee977a1cf3821d99d6322ef239de1dad Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2543/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f12ba0bb15..e23052209e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4289,7 +4289,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From bf239f88d5cfcdc1f9d46fa85d13141f27782cd1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2544/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index a4bc770e2d..a588895fcb 100644
--- a/http.c
+++ b/http.c
@@ -3,6 +3,7 @@
 #include "sideband.h"
 #include "run-command.h"
 #include "url.h"
+#include "exec_cmd.h"
 
 int data_received;
 int active_requests;
@@ -160,6 +161,18 @@ static char *git_getpass_with_description(const char *what, const char *desc)
 	return xstrdup(r);
 }
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -167,17 +180,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 5cf00b32a65767131d819ce44eb3361ab5e37e14 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2545/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index c59b0c98fe..68fd050e94 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From 352f3d032a1cb6e74151e0370640aced056493e2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2546/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 6099521224..99d8fecfad 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -401,7 +401,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From c592e94cd3ab0009a4a01c5ab6f64d1d8987ac3c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2547/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 988ea1d332..133c4583b7 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "dir.h"
 #include "thread-utils.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -206,6 +207,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -216,6 +233,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -529,6 +549,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -995,6 +1018,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From aa1c11fa7b95fa0d80209a91aff871b28b9cc4d5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2548/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 58505b07eb..fdc777d287 100644
--- a/Makefile
+++ b/Makefile
@@ -274,7 +274,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From 68acf508aa32c2d83a05e46f25b7d1ef9e500e32 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2549/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8cb35b693f..2106ce5f78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 64f7bec55a85bce22925d82586603619850dc9f6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2550/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index fdc777d287..03e64695fd 100644
--- a/Makefile
+++ b/Makefile
@@ -1945,7 +1945,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -1985,6 +1985,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 30d3f9ea5432dd459800a32462714464280e1809 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2551/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 63849836c8..2ef2ec912e 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From ed7b27526008d4b26762bb38b40e342df8089321 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2552/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 133c4583b7..63b00f8fab 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1083,6 +1083,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From d3d677e244e131b6da6b09a503239068bd3caf2b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2553/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 63b00f8fab..b18491bc8c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1083,7 +1083,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From 8089c85c07fd6b3df6f55bafce8adf057e271161 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2554/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 2e1f25091e68785a19df3feb308839db3c38f3b6 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2555/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2106ce5f78..bf9e01fb1a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 3f65607535539f313ecf00c8c8c7b1d1f6bcb1b2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2556/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From d3abd848ae3adab36683d5d1398e6534cb1b484d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2557/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From fece0cb400a287bbbacd4773eb9881c44061b4e1 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2558/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2559/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93635..73f41482a8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2560/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 3e4b79023d53d6499d13623127408f85d6bb9aee Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2561/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2562/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9464a1391d..bb6cd9ab7b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 27414094c465f232fff213153d2f55167862e403 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2563/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 03e64695fd..70edb11c55 100644
--- a/Makefile
+++ b/Makefile
@@ -1126,6 +1126,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1218,6 +1219,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 18cf3214bfce51877c76da97fb43966100887b5c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2564/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 9d46513b6e9f6c6361d37bb44a57d9326f768543 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2565/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From ab7ab7a0f60d5bb54509d54018c649d04b635c53 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2566/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From c45b052724febee6de3efe25b92e9f74165883fc Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2567/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 8258c82410351e0d8c73e3826a182c718b2446e4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2568/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bf9e01fb1a..87c8a2c0e1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From e0f249288266b008558e9a9beb31ddbf72153269 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2569/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 87c8a2c0e1..509103b676 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index bb6cd9ab7b..90b53015bb 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -328,22 +328,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 1d9ac661a1dcafd7bed169db305695e613e8f8c6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2570/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 509103b676..370cf8885c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 3efcd98f5bdc49f660e8cef95fa7b47da443769c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2571/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e23052209e..305a5834e5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6468,7 +6468,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6516,6 +6528,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 4654bdda43d67dd3229f373cb939f85a8a4b8e6c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2572/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 305a5834e5..de07d2d566 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,7 +4274,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 77a30dad90647d756b51f7ba64a1b97f4c4b359e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2573/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index de07d2d566..f1ebf7edf1 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6581,7 +6581,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 5084033ed4339d885b0548604b1e139bf03faccc Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2574/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 370cf8885c..9aba372fa5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 5d6f1d961e40db3591d9465f7b85125d5660370a Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2575/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 90b53015bb..cdaa7ba476 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 5d1168b5e2df4a90c5856bda8dce37a6c1511517 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2576/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index e1da468766..f440fcd23c 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 9868a0bfb4..484ff0905e 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 dry_run=
 while :
@@ -105,7 +106,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -270,7 +276,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From ae69aaf4868485260f8a1803969c089228961e64 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2577/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5fbefef621..da824c92ec 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -684,6 +684,7 @@ branch..rebase::
 	When true, rebase the branch  on top of the fetched branch,
 	instead of merging the default branch from the default remote when
 	"git pull" is run.
+	When the value is `interactive`, the rebase is run in interactive mode.
 	*NOTE*: this is a possibly dangerous operation; do *not* use
 	it unless you understand the implications (see linkgit:git-rebase[1]
 	for details).
diff --git a/git-pull.sh b/git-pull.sh
index 484ff0905e..ffdc5eff98 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 dry_run=
 while :
 do

From fd6f6aad1caf8a5ba46b2afd1d11c31118fc91f7 Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:42 +0100
Subject: [PATCH 2578/3720] Compile fix for MSVC: Do not include
 sys/resources.h

Do not include header files when compiling with MSVC that do not
exist and which are also not included when compiling with MINGW.
A direct consequence is that git can be compiled again with MSVC
because the missing "sys/resources.h" is no longer included.

Instead of current

	#ifndef mingw32 is the only one that is strange
        ... everything for systems that is not strange ...
        #else
        ... include mingw specific tweaks ...
        #endif
        #ifdef msvc is also strange
        ... include msvc specific tweaks ...
        #endif

it turns things around and says what it wants to achieve in a more direct
way, i.e.

	#if mingw32
        #include "compat/mingw.h"
	#elif msvc
        #include "compat/msvc.h"
	#else
        ... all the others ...
	#endif

which makes it look simpler.

Signed-off-by: Vincent van Ravesteijn 
Helped-by: Junio C Hamano 
Signed-off-by: Erik Faye-Lund 
---
 git-compat-util.h | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index 8c9d4ed1e5..0135dcc950 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -116,7 +116,12 @@
 #else
 #include 
 #endif
-#ifndef __MINGW32__
+#if defined(__MINGW32__)
+/* pull in Windows compatibility stuff */
+#include "compat/mingw.h"
+#elif defined(_MSC_VER)
+#include "compat/msvc.h"
+#else
 #include 
 #include 
 #include 
@@ -145,12 +150,6 @@
 #include 
 #define _ALL_SOURCE 1
 #endif
-#else 	/* __MINGW32__ */
-/* pull in Windows compatibility stuff */
-#include "compat/mingw.h"
-#endif	/* __MINGW32__ */
-#ifdef _MSC_VER
-#include "compat/msvc.h"
 #endif
 
 #ifndef NO_LIBGEN_H

From 18f5b9e3170b58d99f6f215fb0e2c749afbc4a91 Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:43 +0100
Subject: [PATCH 2579/3720] Compile fix for MSVC: Include 

This include is needed for _commit(..) which is used in mingw.h.

Signed-off-by: Vincent van Ravesteijn 
Signed-off-by: Erik Faye-Lund 
---
 compat/msvc.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/compat/msvc.h b/compat/msvc.h
index a33b01c032..aa4b56315a 100644
--- a/compat/msvc.h
+++ b/compat/msvc.h
@@ -4,6 +4,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* porting function */
 #define inline __inline

From 0a6d1482326a97e3beaa8cde6841ad4019aa8c07 Mon Sep 17 00:00:00 2001
From: Vincent van Ravesteijn 
Date: Mon, 31 Oct 2011 20:12:44 +0100
Subject: [PATCH 2580/3720] MSVC: Remove unneeded header stubs

These headers are no longer needed since they are no longer
unnecessarily included in git-compat-util.h.

Signed-off-by: Vincent van Ravesteijn 
Signed-off-by: Erik Faye-Lund 
---
 compat/vcbuild/include/arpa/inet.h   | 1 -
 compat/vcbuild/include/grp.h         | 1 -
 compat/vcbuild/include/inttypes.h    | 1 -
 compat/vcbuild/include/netdb.h       | 1 -
 compat/vcbuild/include/netinet/in.h  | 1 -
 compat/vcbuild/include/netinet/tcp.h | 1 -
 compat/vcbuild/include/pwd.h         | 1 -
 compat/vcbuild/include/sys/ioctl.h   | 1 -
 compat/vcbuild/include/sys/select.h  | 1 -
 compat/vcbuild/include/sys/socket.h  | 1 -
 compat/vcbuild/include/sys/wait.h    | 1 -
 compat/vcbuild/include/termios.h     | 1 -
 12 files changed, 12 deletions(-)
 delete mode 100644 compat/vcbuild/include/arpa/inet.h
 delete mode 100644 compat/vcbuild/include/grp.h
 delete mode 100644 compat/vcbuild/include/inttypes.h
 delete mode 100644 compat/vcbuild/include/netdb.h
 delete mode 100644 compat/vcbuild/include/netinet/in.h
 delete mode 100644 compat/vcbuild/include/netinet/tcp.h
 delete mode 100644 compat/vcbuild/include/pwd.h
 delete mode 100644 compat/vcbuild/include/sys/ioctl.h
 delete mode 100644 compat/vcbuild/include/sys/select.h
 delete mode 100644 compat/vcbuild/include/sys/socket.h
 delete mode 100644 compat/vcbuild/include/sys/wait.h
 delete mode 100644 compat/vcbuild/include/termios.h

diff --git a/compat/vcbuild/include/arpa/inet.h b/compat/vcbuild/include/arpa/inet.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/arpa/inet.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/grp.h b/compat/vcbuild/include/grp.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/grp.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/inttypes.h b/compat/vcbuild/include/inttypes.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/inttypes.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netdb.h b/compat/vcbuild/include/netdb.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netdb.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netinet/in.h b/compat/vcbuild/include/netinet/in.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netinet/in.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/netinet/tcp.h b/compat/vcbuild/include/netinet/tcp.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/netinet/tcp.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/pwd.h b/compat/vcbuild/include/pwd.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/pwd.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/ioctl.h b/compat/vcbuild/include/sys/ioctl.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/ioctl.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/select.h b/compat/vcbuild/include/sys/select.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/select.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/socket.h b/compat/vcbuild/include/sys/socket.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/socket.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/sys/wait.h b/compat/vcbuild/include/sys/wait.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/sys/wait.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/termios.h b/compat/vcbuild/include/termios.h
deleted file mode 100644
index 0d8552a2c6..0000000000
--- a/compat/vcbuild/include/termios.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */

From 9ca803910f3625bf686699f6b0bf71a8c68bccae Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 2581/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index cdaa7ba476..ee76d6bf97 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 0135dcc950..cd289daa21 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From a49c818092d621d195729cc0e8d05ca5d60b7c58 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 2582/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From 778774d7f70bf148ae8631e39eccf0e56757d7b2 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 2583/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 70edb11c55..483ef5cfde 100644
--- a/Makefile
+++ b/Makefile
@@ -1124,6 +1124,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From 9e47e31d380058edd90a94c0309902a1e0d8cdd4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 2584/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From 00e3ef17287395b894daa02a064f24531eb714e7 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Tue, 8 Nov 2011 16:05:43 -0800
Subject: [PATCH 2585/3720] Revert the previous "signed commit" attempt

Signed-off-by: Junio C Hamano 
---
 Makefile                         |   2 -
 builtin/commit-tree.c            |  24 +-----
 builtin/commit.c                 |  12 +--
 builtin/merge.c                  |  16 +---
 builtin/tag.c                    |  76 +++++++++++++++--
 builtin/verify-tag.c             |  35 ++++++--
 commit.c                         |  77 +----------------
 commit.h                         |   5 +-
 gpg-interface.c                  | 138 -------------------------------
 gpg-interface.h                  |  10 ---
 log-tree.c                       |  39 ---------
 notes-cache.c                    |   2 +-
 notes-merge.c                    |   2 +-
 pretty.c                         |  86 -------------------
 revision.c                       |   2 -
 revision.h                       |   1 -
 t/lib-gpg.sh                     |  29 -------
 t/t7004-tag.sh                   |  29 ++++++-
 t/{lib-gpg => t7004}/pubring.gpg | Bin
 t/{lib-gpg => t7004}/random_seed | Bin
 t/{lib-gpg => t7004}/secring.gpg | Bin
 t/{lib-gpg => t7004}/trustdb.gpg | Bin
 t/t7510-signed-commit.sh         |  71 ----------------
 tag.c                            |   5 --
 24 files changed, 139 insertions(+), 522 deletions(-)
 delete mode 100644 gpg-interface.c
 delete mode 100644 gpg-interface.h
 delete mode 100644 t/lib-gpg.sh
 rename t/{lib-gpg => t7004}/pubring.gpg (100%)
 rename t/{lib-gpg => t7004}/random_seed (100%)
 rename t/{lib-gpg => t7004}/secring.gpg (100%)
 rename t/{lib-gpg => t7004}/trustdb.gpg (100%)
 delete mode 100755 t/t7510-signed-commit.sh

diff --git a/Makefile b/Makefile
index 2183223759..8d6d4515d2 100644
--- a/Makefile
+++ b/Makefile
@@ -530,7 +530,6 @@ LIB_H += exec_cmd.h
 LIB_H += fsck.h
 LIB_H += gettext.h
 LIB_H += git-compat-util.h
-LIB_H += gpg-interface.h
 LIB_H += graph.h
 LIB_H += grep.h
 LIB_H += hash.h
@@ -621,7 +620,6 @@ LIB_OBJS += entry.o
 LIB_OBJS += environment.o
 LIB_OBJS += exec_cmd.o
 LIB_OBJS += fsck.o
-LIB_OBJS += gpg-interface.o
 LIB_OBJS += graph.o
 LIB_OBJS += grep.o
 LIB_OBJS += hash.o
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index a17811f958..d083795e26 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -8,9 +8,8 @@
 #include "tree.h"
 #include "builtin.h"
 #include "utf8.h"
-#include "gpg-interface.h"
 
-static const char commit_tree_usage[] = "git commit-tree [-S]  [(-p )...] < changelog";
+static const char commit_tree_usage[] = "git commit-tree  [(-p )...] < changelog";
 
 static void new_parent(struct commit *parent, struct commit_list **parents_p)
 {
@@ -26,14 +25,6 @@ static void new_parent(struct commit *parent, struct commit_list **parents_p)
 	commit_list_insert(parent, parents_p);
 }
 
-static int commit_tree_config(const char *var, const char *value, void *cb)
-{
-	int status = git_gpg_config(var, value, NULL);
-	if (status)
-		return status;
-	return git_default_config(var, value, cb);
-}
-
 int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 {
 	int i;
@@ -41,19 +32,11 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 	unsigned char tree_sha1[20];
 	unsigned char commit_sha1[20];
 	struct strbuf buffer = STRBUF_INIT;
-	const char *sign_commit = NULL;
 
-	git_config(commit_tree_config, NULL);
+	git_config(git_default_config, NULL);
 
 	if (argc < 2 || !strcmp(argv[1], "-h"))
 		usage(commit_tree_usage);
-
-	if (!memcmp(argv[1], "-S", 2)) {
-		sign_commit = argv[1] + 2;
-		argv++;
-		argc--;
-	}
-
 	if (get_sha1(argv[1], tree_sha1))
 		die("Not a valid object name %s", argv[1]);
 
@@ -73,8 +56,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 	if (strbuf_read(&buffer, 0, 0) < 0)
 		die_errno("git commit-tree: failed to read");
 
-	if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1,
-			NULL, sign_commit)) {
+	if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
 		strbuf_release(&buffer);
 		return 1;
 	}
diff --git a/builtin/commit.c b/builtin/commit.c
index 90cf7e812b..cbc9613ec6 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -26,7 +26,6 @@
 #include "unpack-trees.h"
 #include "quote.h"
 #include "submodule.h"
-#include "gpg-interface.h"
 
 static const char * const builtin_commit_usage[] = {
 	"git commit [options] [--] ...",
@@ -86,8 +85,6 @@ static int all, edit_flag, also, interactive, patch_interactive, only, amend, si
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int no_post_rewrite, allow_empty_message;
 static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
-static char *sign_commit;
-
 /*
  * The default commit message cleanup mode will remove the lines
  * beginning with # (shell comments) and leading and trailing
@@ -147,8 +144,6 @@ static struct option builtin_commit_options[] = {
 	OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
 	OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
 	OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
-	{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
-	  "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
 	/* end commit message options */
 
 	OPT_GROUP("Commit contents options"),
@@ -1328,7 +1323,6 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
 static int git_commit_config(const char *k, const char *v, void *cb)
 {
 	struct wt_status *s = cb;
-	int status;
 
 	if (!strcmp(k, "commit.template"))
 		return git_config_pathname(&template_file, k, v);
@@ -1336,9 +1330,7 @@ static int git_commit_config(const char *k, const char *v, void *cb)
 		include_status = git_config_bool(k, v);
 		return 0;
 	}
-	status = git_gpg_config(k, v, NULL);
-	if (status)
-		return status;
+
 	return git_status_config(k, v, s);
 }
 
@@ -1489,7 +1481,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 	}
 
 	if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1,
-			author_ident.buf, sign_commit)) {
+			author_ident.buf)) {
 		rollback_index_files();
 		die(_("failed to write commit object"));
 	}
diff --git a/builtin/merge.c b/builtin/merge.c
index 53cff0266c..ab4077f272 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -26,7 +26,6 @@
 #include "merge-recursive.h"
 #include "resolve-undo.h"
 #include "remote.h"
-#include "gpg-interface.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -64,7 +63,6 @@ static int allow_rerere_auto;
 static int abort_current_merge;
 static int show_progress = -1;
 static int default_to_upstream;
-static const char *sign_commit;
 
 static struct strategy all_strategy[] = {
 	{ "recursive",  DEFAULT_TWOHEAD | NO_TRIVIAL },
@@ -208,8 +206,6 @@ static struct option builtin_merge_options[] = {
 	OPT_BOOLEAN(0, "abort", &abort_current_merge,
 		"abort the current in-progress merge"),
 	OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
-	{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
-	  "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
 	OPT_END()
 };
 
@@ -529,8 +525,6 @@ static void parse_branch_merge_options(char *bmo)
 
 static int git_merge_config(const char *k, const char *v, void *cb)
 {
-	int status;
-
 	if (branch && !prefixcmp(k, "branch.") &&
 		!prefixcmp(k + 7, branch) &&
 		!strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
@@ -568,10 +562,6 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		default_to_upstream = git_config_bool(k, v);
 		return 0;
 	}
-
-	status = git_gpg_config(k, v, NULL);
-	if (status)
-		return status;
 	return git_diff_ui_config(k, v, cb);
 }
 
@@ -880,8 +870,7 @@ static int merge_trivial(void)
 	parent->next->item = remoteheads->item;
 	parent->next->next = NULL;
 	run_prepare_commit_msg();
-	commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL,
-		    sign_commit);
+	commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
 	finish(result_commit, "In-index merge");
 	drop_save();
 	return 0;
@@ -911,8 +900,7 @@ static int finish_automerge(struct commit_list *common,
 	free_commit_list(remoteheads);
 	strbuf_addch(&merge_msg, '\n');
 	run_prepare_commit_msg();
-	commit_tree(merge_msg.buf, result_tree, parents, result_commit,
-		    NULL, sign_commit);
+	commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
 	strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
 	finish(result_commit, buf.buf);
 	strbuf_release(&buf);
diff --git a/builtin/tag.c b/builtin/tag.c
index fb0d4a1648..667515e527 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -14,7 +14,6 @@
 #include "parse-options.h"
 #include "diff.h"
 #include "revision.h"
-#include "gpg-interface.h"
 
 static const char * const git_tag_usage[] = {
 	"git tag [-a|-s|-u ] [-f] [-m |-F ]  []",
@@ -24,6 +23,8 @@ static const char * const git_tag_usage[] = {
 	NULL
 };
 
+static char signingkey[1000];
+
 struct tag_filter {
 	const char **patterns;
 	int lines;
@@ -207,7 +208,60 @@ static int verify_tag(const char *name, const char *ref,
 
 static int do_sign(struct strbuf *buffer)
 {
-	return sign_buffer(buffer, buffer, get_signing_key());
+	struct child_process gpg;
+	const char *args[4];
+	char *bracket;
+	int len;
+	int i, j;
+
+	if (!*signingkey) {
+		if (strlcpy(signingkey, git_committer_info(IDENT_ERROR_ON_NO_NAME),
+				sizeof(signingkey)) > sizeof(signingkey) - 1)
+			return error(_("committer info too long."));
+		bracket = strchr(signingkey, '>');
+		if (bracket)
+			bracket[1] = '\0';
+	}
+
+	/* When the username signingkey is bad, program could be terminated
+	 * because gpg exits without reading and then write gets SIGPIPE. */
+	signal(SIGPIPE, SIG_IGN);
+
+	memset(&gpg, 0, sizeof(gpg));
+	gpg.argv = args;
+	gpg.in = -1;
+	gpg.out = -1;
+	args[0] = "gpg";
+	args[1] = "-bsau";
+	args[2] = signingkey;
+	args[3] = NULL;
+
+	if (start_command(&gpg))
+		return error(_("could not run gpg."));
+
+	if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
+		close(gpg.in);
+		close(gpg.out);
+		finish_command(&gpg);
+		return error(_("gpg did not accept the tag data"));
+	}
+	close(gpg.in);
+	len = strbuf_read(buffer, gpg.out, 1024);
+	close(gpg.out);
+
+	if (finish_command(&gpg) || !len || len < 0)
+		return error(_("gpg failed to sign the tag"));
+
+	/* Strip CR from the line endings, in case we are on Windows. */
+	for (i = j = 0; i < buffer->len; i++)
+		if (buffer->buf[i] != '\r') {
+			if (i != j)
+				buffer->buf[j] = buffer->buf[i];
+			j++;
+		}
+	strbuf_setlen(buffer, j);
+
+	return 0;
 }
 
 static const char tag_template[] =
@@ -216,11 +270,21 @@ static const char tag_template[] =
 	"# Write a tag message\n"
 	"#\n");
 
+static void set_signingkey(const char *value)
+{
+	if (strlcpy(signingkey, value, sizeof(signingkey)) >= sizeof(signingkey))
+		die(_("signing key value too long (%.10s...)"), value);
+}
+
 static int git_tag_config(const char *var, const char *value, void *cb)
 {
-	int status = git_gpg_config(var, value, cb);
-	if (status)
-		return status;
+	if (!strcmp(var, "user.signingkey")) {
+		if (!value)
+			return config_error_nonbool(var);
+		set_signingkey(value);
+		return 0;
+	}
+
 	return git_default_config(var, value, cb);
 }
 
@@ -399,7 +463,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
 	if (keyid) {
 		sign = 1;
-		set_signing_key(keyid);
+		set_signingkey(keyid);
 	}
 	if (sign)
 		annotate = 1;
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 28c2174338..3134766049 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -11,7 +11,6 @@
 #include "run-command.h"
 #include 
 #include "parse-options.h"
-#include "gpg-interface.h"
 
 static const char * const verify_tag_usage[] = {
 		"git verify-tag [-v|--verbose] ...",
@@ -20,16 +19,42 @@ static const char * const verify_tag_usage[] = {
 
 static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
 {
-	int len;
+	struct child_process gpg;
+	const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
+	char path[PATH_MAX];
+	size_t len;
+	int fd, ret;
 
+	fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
+	if (fd < 0)
+		return error("could not create temporary file '%s': %s",
+						path, strerror(errno));
+	if (write_in_full(fd, buf, size) < 0)
+		return error("failed writing temporary file '%s': %s",
+						path, strerror(errno));
+	close(fd);
+
+	/* find the length without signature */
 	len = parse_signature(buf, size);
 	if (verbose)
 		write_in_full(1, buf, len);
 
-	if (size == len)
-		return error("no signature found");
+	memset(&gpg, 0, sizeof(gpg));
+	gpg.argv = args_gpg;
+	gpg.in = -1;
+	args_gpg[2] = path;
+	if (start_command(&gpg)) {
+		unlink(path);
+		return error("could not run gpg.");
+	}
 
-	return verify_signed_buffer(buf, len, buf + len, size - len, NULL);
+	write_in_full(gpg.in, buf, len);
+	close(gpg.in);
+	ret = finish_command(&gpg);
+
+	unlink_or_warn(path);
+
+	return ret;
 }
 
 static int verify_tag(const char *name, int verbose)
diff --git a/commit.c b/commit.c
index 09693f78d9..97b43279cd 100644
--- a/commit.c
+++ b/commit.c
@@ -6,7 +6,6 @@
 #include "diff.h"
 #include "revision.h"
 #include "notes.h"
-#include "gpg-interface.h"
 
 int save_commit_buffer = 1;
 
@@ -815,77 +814,6 @@ struct commit_list *reduce_heads(struct commit_list *heads)
 	return result;
 }
 
-static const char gpg_sig_header[] = "gpgsig ";
-static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;
-
-static int do_sign_commit(struct strbuf *buf, const char *keyid)
-{
-	struct strbuf sig = STRBUF_INIT;
-	int inspos, copypos;
-
-	/* find the end of the header */
-	inspos = strstr(buf->buf, "\n\n") - buf->buf + 1;
-
-	if (!keyid || !*keyid)
-		keyid = get_signing_key();
-	if (sign_buffer(buf, &sig, keyid)) {
-		strbuf_release(&sig);
-		return -1;
-	}
-
-	for (copypos = 0; sig.buf[copypos]; ) {
-		const char *bol = sig.buf + copypos;
-		const char *eol = strchrnul(bol, '\n');
-		int len = (eol - bol) + !!*eol;
-
-		strbuf_insert(buf, inspos, gpg_sig_header, gpg_sig_header_len);
-		inspos += gpg_sig_header_len;
-		strbuf_insert(buf, inspos, bol, len);
-		inspos += len;
-		copypos += len;
-	}
-	strbuf_release(&sig);
-	return 0;
-}
-
-int parse_signed_commit(const unsigned char *sha1,
-			struct strbuf *payload, struct strbuf *signature)
-{
-	unsigned long size;
-	enum object_type type;
-	char *buffer = read_sha1_file(sha1, &type, &size);
-	int saw_signature = -1;
-	char *line, *tail;
-
-	if (!buffer || type != OBJ_COMMIT)
-		goto cleanup;
-
-	line = buffer;
-	tail = buffer + size;
-	saw_signature = 0;
-	while (line < tail) {
-		char *next = memchr(line, '\n', tail - line);
-		if (!next)
-			next = tail;
-		else
-			next++;
-		if (!prefixcmp(line, gpg_sig_header)) {
-			const char *sig = line + gpg_sig_header_len;
-			strbuf_add(signature, sig, next - sig);
-			saw_signature = 1;
-		} else {
-			if (*line == '\n')
-				/* dump the whole remainder of the buffer */
-				next = tail;
-			strbuf_add(payload, line, next - line);
-		}
-		line = next;
-	}
- cleanup:
-	free(buffer);
-	return saw_signature;
-}
-
 static const char commit_utf8_warn[] =
 "Warning: commit message does not conform to UTF-8.\n"
 "You may want to amend it after fixing the message, or set the config\n"
@@ -893,7 +821,7 @@ static const char commit_utf8_warn[] =
 
 int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret,
-		const char *author, const char *sign_commit)
+		const char *author)
 {
 	int result;
 	int encoding_is_utf8;
@@ -936,9 +864,6 @@ int commit_tree(const char *msg, unsigned char *tree,
 	if (encoding_is_utf8 && !is_utf8(buffer.buf))
 		fprintf(stderr, commit_utf8_warn);
 
-	if (sign_commit && do_sign_commit(&buffer, sign_commit))
-		return -1;
-
 	result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
 	strbuf_release(&buffer);
 	return result;
diff --git a/commit.h b/commit.h
index 1885471b8b..12d100b8b6 100644
--- a/commit.h
+++ b/commit.h
@@ -175,9 +175,6 @@ struct commit_list *reduce_heads(struct commit_list *heads);
 
 extern int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret,
-		       const char *author, const char *sign_commit);
-
-extern int parse_signed_commit(const unsigned char *sha1,
-			       struct strbuf *message, struct strbuf *signature);
+		const char *author);
 
 #endif /* COMMIT_H */
diff --git a/gpg-interface.c b/gpg-interface.c
deleted file mode 100644
index ff232c8c5d..0000000000
--- a/gpg-interface.c
+++ /dev/null
@@ -1,138 +0,0 @@
-#include "cache.h"
-#include "run-command.h"
-#include "strbuf.h"
-#include "gpg-interface.h"
-#include "sigchain.h"
-
-static char *configured_signing_key;
-
-void set_signing_key(const char *key)
-{
-	free(configured_signing_key);
-	configured_signing_key = xstrdup(key);
-}
-
-int git_gpg_config(const char *var, const char *value, void *cb)
-{
-	if (!strcmp(var, "user.signingkey")) {
-		if (!value)
-			return config_error_nonbool(var);
-		set_signing_key(value);
-	}
-	return 0;
-}
-
-const char *get_signing_key(void)
-{
-	if (configured_signing_key)
-		return configured_signing_key;
-	return git_committer_info(IDENT_ERROR_ON_NO_NAME|IDENT_NO_DATE);
-}
-
-/*
- * Create a detached signature for the contents of "buffer" and append
- * it after "signature"; "buffer" and "signature" can be the same
- * strbuf instance, which would cause the detached signature appended
- * at the end.
- */
-int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
-{
-	struct child_process gpg;
-	const char *args[4];
-	ssize_t len;
-	size_t i, j, bottom;
-
-	memset(&gpg, 0, sizeof(gpg));
-	gpg.argv = args;
-	gpg.in = -1;
-	gpg.out = -1;
-	args[0] = "gpg";
-	args[1] = "-bsau";
-	args[2] = signing_key;
-	args[3] = NULL;
-
-	if (start_command(&gpg))
-		return error(_("could not run gpg."));
-
-	/*
-	 * When the username signingkey is bad, program could be terminated
-	 * because gpg exits without reading and then write gets SIGPIPE.
-	 */
-	sigchain_push(SIGPIPE, SIG_IGN);
-
-	if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
-		close(gpg.in);
-		close(gpg.out);
-		finish_command(&gpg);
-		return error(_("gpg did not accept the data"));
-	}
-	close(gpg.in);
-
-	bottom = signature->len;
-	len = strbuf_read(signature, gpg.out, 1024);
-	close(gpg.out);
-
-	sigchain_pop(SIGPIPE);
-
-	if (finish_command(&gpg) || !len || len < 0)
-		return error(_("gpg failed to sign the data"));
-
-	/* Strip CR from the line endings, in case we are on Windows. */
-	for (i = j = bottom; i < signature->len; i++)
-		if (signature->buf[i] != '\r') {
-			if (i != j)
-				signature->buf[j] = signature->buf[i];
-			j++;
-		}
-	strbuf_setlen(signature, j);
-
-	return 0;
-}
-
-/*
- * Run "gpg" to see if the payload matches the detached signature.
- * gpg_output_to tells where the output from "gpg" should go:
- *   < 0: /dev/null
- *   = 0: standard error of the calling process
- *   > 0: the specified file descriptor
- */
-int verify_signed_buffer(const char *payload, size_t payload_size,
-			 const char *signature, size_t signature_size,
-			 struct strbuf *gpg_output)
-{
-	struct child_process gpg;
-	const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
-	char path[PATH_MAX];
-	int fd, ret;
-
-	fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
-	if (fd < 0)
-		return error("could not create temporary file '%s': %s",
-			     path, strerror(errno));
-	if (write_in_full(fd, signature, signature_size) < 0)
-		return error("failed writing detached signature to '%s': %s",
-			     path, strerror(errno));
-	close(fd);
-
-	memset(&gpg, 0, sizeof(gpg));
-	gpg.argv = args_gpg;
-	gpg.in = -1;
-	if (gpg_output)
-		gpg.err = -1;
-	args_gpg[2] = path;
-	if (start_command(&gpg)) {
-		unlink(path);
-		return error("could not run gpg.");
-	}
-
-	write_in_full(gpg.in, payload, payload_size);
-	close(gpg.in);
-
-	if (gpg_output)
-		strbuf_read(gpg_output, gpg.err, 0);
-	ret = finish_command(&gpg);
-
-	unlink_or_warn(path);
-
-	return ret;
-}
diff --git a/gpg-interface.h b/gpg-interface.h
deleted file mode 100644
index b9c36088ce..0000000000
--- a/gpg-interface.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef GPG_INTERFACE_H
-#define GPG_INTERFACE_H
-
-extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key);
-extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output);
-extern int git_gpg_config(const char *, const char *, void *);
-extern void set_signing_key(const char *);
-extern const char *get_signing_key(void);
-
-#endif
diff --git a/log-tree.c b/log-tree.c
index f7b6976d9f..24c295ea1d 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -8,7 +8,6 @@
 #include "refs.h"
 #include "string-list.h"
 #include "color.h"
-#include "gpg-interface.h"
 
 struct decoration name_decoration = { "object names" };
 
@@ -396,41 +395,6 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 	*extra_headers_p = extra_headers;
 }
 
-static void show_signature(struct rev_info *opt, struct commit *commit)
-{
-	struct strbuf payload = STRBUF_INIT;
-	struct strbuf signature = STRBUF_INIT;
-	struct strbuf gpg_output = STRBUF_INIT;
-	int status;
-	const char *color, *reset, *bol, *eol;
-
-	if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0)
-		goto out;
-
-	status = verify_signed_buffer(payload.buf, payload.len,
-				      signature.buf, signature.len,
-				      &gpg_output);
-	if (status && !gpg_output.len)
-		strbuf_addstr(&gpg_output, "No signature\n");
-
-	color = diff_get_color_opt(&opt->diffopt,
-				   status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
-	reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
-
-	bol = gpg_output.buf;
-	while (*bol) {
-		eol = strchrnul(bol, '\n');
-		printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
-		       *eol ? "\n" : "");
-		bol = (*eol) ? (eol + 1) : eol;
-	}
-
- out:
-	strbuf_release(&gpg_output);
-	strbuf_release(&payload);
-	strbuf_release(&signature);
-}
-
 void show_log(struct rev_info *opt)
 {
 	struct strbuf msgbuf = STRBUF_INIT;
@@ -538,9 +502,6 @@ void show_log(struct rev_info *opt)
 		}
 	}
 
-	if (opt->show_signature)
-		show_signature(opt, commit);
-
 	if (!commit->buffer)
 		return;
 
diff --git a/notes-cache.c b/notes-cache.c
index c36a960bc3..4c8984ede1 100644
--- a/notes-cache.c
+++ b/notes-cache.c
@@ -56,7 +56,7 @@ int notes_cache_write(struct notes_cache *c)
 
 	if (write_notes_tree(&c->tree, tree_sha1))
 		return -1;
-	if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL, NULL) < 0)
+	if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL) < 0)
 		return -1;
 	if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
 		       0, QUIET_ON_ERR) < 0)
diff --git a/notes-merge.c b/notes-merge.c
index c29c434156..e1aaf43b43 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -546,7 +546,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
 		/* else: t->ref points to nothing, assume root/orphan commit */
 	}
 
-	if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL))
+	if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL))
 		die("Failed to commit notes tree to database");
 }
 
diff --git a/pretty.c b/pretty.c
index 392d656595..f45eb54e4c 100644
--- a/pretty.c
+++ b/pretty.c
@@ -9,7 +9,6 @@
 #include "notes.h"
 #include "color.h"
 #include "reflog-walk.h"
-#include "gpg-interface.h"
 
 static char *user_format;
 static struct cmt_fmt_map {
@@ -641,12 +640,6 @@ struct format_commit_context {
 	const struct pretty_print_context *pretty_ctx;
 	unsigned commit_header_parsed:1;
 	unsigned commit_message_parsed:1;
-	unsigned commit_signature_parsed:1;
-	struct {
-		char *gpg_output;
-		char good_bad;
-		char *signer;
-	} signature;
 	char *message;
 	size_t width, indent1, indent2;
 
@@ -829,59 +822,6 @@ static void rewrap_message_tail(struct strbuf *sb,
 	c->indent2 = new_indent2;
 }
 
-static struct {
-	char result;
-	const char *check;
-} signature_check[] = {
-	{ 'G', ": Good signature from " },
-	{ 'B', ": BAD signature from " },
-};
-
-static void parse_signature_lines(struct format_commit_context *ctx)
-{
-	const char *buf = ctx->signature.gpg_output;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
-		const char *found = strstr(buf, signature_check[i].check);
-		const char *next;
-		if (!found)
-			continue;
-		ctx->signature.good_bad = signature_check[i].result;
-		found += strlen(signature_check[i].check);
-		next = strchrnul(found, '\n');
-		ctx->signature.signer = xmemdupz(found, next - found);
-		break;
-	}
-}
-
-static void parse_commit_signature(struct format_commit_context *ctx)
-{
-	struct strbuf payload = STRBUF_INIT;
-	struct strbuf signature = STRBUF_INIT;
-	struct strbuf gpg_output = STRBUF_INIT;
-	int status;
-
-	ctx->commit_signature_parsed = 1;
-
-	if (parse_signed_commit(ctx->commit->object.sha1,
-				&payload, &signature) <= 0)
-		goto out;
-	status = verify_signed_buffer(payload.buf, payload.len,
-				      signature.buf, signature.len,
-				      &gpg_output);
-	if (status && !gpg_output.len)
-		goto out;
-	ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
-	parse_signature_lines(ctx);
-
- out:
-	strbuf_release(&gpg_output);
-	strbuf_release(&payload);
-	strbuf_release(&signature);
-}
-
-
 static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 				void *context)
 {
@@ -1034,30 +974,6 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 		return 0;
 	}
 
-	if (placeholder[0] == 'G') {
-		if (!c->commit_signature_parsed)
-			parse_commit_signature(c);
-		switch (placeholder[1]) {
-		case 'G':
-			if (c->signature.gpg_output)
-				strbuf_addstr(sb, c->signature.gpg_output);
-			break;
-		case '?':
-			switch (c->signature.good_bad) {
-			case 'G':
-			case 'B':
-				strbuf_addch(sb, c->signature.good_bad);
-			}
-			break;
-		case 'S':
-			if (c->signature.signer)
-				strbuf_addstr(sb, c->signature.signer);
-			break;
-		}
-		return 2;
-	}
-
-
 	/* For the rest we have to parse the commit header. */
 	if (!c->commit_header_parsed)
 		parse_commit_header(c);
@@ -1198,8 +1114,6 @@ void format_commit_message(const struct commit *commit,
 
 	if (context.message != commit->buffer)
 		free(context.message);
-	free(context.signature.gpg_output);
-	free(context.signature.signer);
 }
 
 static void pp_header(const struct pretty_print_context *pp,
diff --git a/revision.c b/revision.c
index 860a3128a3..c46cfaa3e4 100644
--- a/revision.c
+++ b/revision.c
@@ -1381,8 +1381,6 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->show_notes = 1;
 		revs->show_notes_given = 1;
 		revs->notes_opt.use_default_notes = 1;
-	} else if (!strcmp(arg, "--show-signature")) {
-		revs->show_signature = 1;
 	} else if (!prefixcmp(arg, "--show-notes=") ||
 		   !prefixcmp(arg, "--notes=")) {
 		struct strbuf buf = STRBUF_INIT;
diff --git a/revision.h b/revision.h
index 198bb95894..3d64adad18 100644
--- a/revision.h
+++ b/revision.h
@@ -89,7 +89,6 @@ struct rev_info {
 			show_merge:1,
 			show_notes:1,
 			show_notes_given:1,
-			show_signature:1,
 			pretty_given:1,
 			abbrev_commit:1,
 			abbrev_commit_given:1,
diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
deleted file mode 100644
index eb09027175..0000000000
--- a/t/lib-gpg.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-
-# Check if gpg is available
-gpg --version >/dev/null 2>/dev/null
-if [ $? -eq 127 ]; then
-	say "# gpg not found - skipping tag signing and verification tests"
-else
-	# As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
-	# the gpg version 1.0.6 didn't parse trust packets correctly, so for
-	# that version, creation of signed tags using the generated key fails.
-	case "$(gpg --version)" in
-	'gpg (GnuPG) 1.0.6'*)
-		say "Skipping signed tag tests, because a bug in 1.0.6 version"
-		;;
-	*)
-		test_set_prereq GPG
-		;;
-	esac
-fi
-
-# key generation info: gpg --homedir t/t7004 --gen-key
-# Type DSA and Elgamal, size 2048 bits, no expiration date.
-# Name and email: C O Mitter 
-# No password given, to enable non-interactive operation.
-
-cp -R "$TEST_DIRECTORY"/lib-gpg ./gpghome
-chmod 0700 gpghome
-GNUPGHOME="$(pwd)/gpghome"
-export GNUPGHOME
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index ded5c86c30..097ce2bc83 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -8,7 +8,6 @@ test_description='git tag
 Tests for operations with tags.'
 
 . ./test-lib.sh
-. "$TEST_DIRECTORY/lib-gpg.sh"
 
 # creating and listing lightweight tags:
 
@@ -586,6 +585,24 @@ test_expect_success \
 	test_cmp expect actual
 '
 
+# subsequent tests require gpg; check if it is available
+gpg --version >/dev/null 2>/dev/null
+if [ $? -eq 127 ]; then
+	say "# gpg not found - skipping tag signing and verification tests"
+else
+	# As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
+	# the gpg version 1.0.6 didn't parse trust packets correctly, so for
+	# that version, creation of signed tags using the generated key fails.
+	case "$(gpg --version)" in
+	'gpg (GnuPG) 1.0.6'*)
+		say "Skipping signed tag tests, because a bug in 1.0.6 version"
+		;;
+	*)
+		test_set_prereq GPG
+		;;
+	esac
+fi
+
 # trying to verify annotated non-signed tags:
 
 test_expect_success GPG \
@@ -608,6 +625,16 @@ test_expect_success GPG \
 
 # creating and verifying signed tags:
 
+# key generation info: gpg --homedir t/t7004 --gen-key
+# Type DSA and Elgamal, size 2048 bits, no expiration date.
+# Name and email: C O Mitter 
+# No password given, to enable non-interactive operation.
+
+cp -R "$TEST_DIRECTORY"/t7004 ./gpghome
+chmod 0700 gpghome
+GNUPGHOME="$(pwd)/gpghome"
+export GNUPGHOME
+
 get_tag_header signed-tag $commit commit $time >expect
 echo 'A signed tag message' >>expect
 echo '-----BEGIN PGP SIGNATURE-----' >>expect
diff --git a/t/lib-gpg/pubring.gpg b/t/t7004/pubring.gpg
similarity index 100%
rename from t/lib-gpg/pubring.gpg
rename to t/t7004/pubring.gpg
diff --git a/t/lib-gpg/random_seed b/t/t7004/random_seed
similarity index 100%
rename from t/lib-gpg/random_seed
rename to t/t7004/random_seed
diff --git a/t/lib-gpg/secring.gpg b/t/t7004/secring.gpg
similarity index 100%
rename from t/lib-gpg/secring.gpg
rename to t/t7004/secring.gpg
diff --git a/t/lib-gpg/trustdb.gpg b/t/t7004/trustdb.gpg
similarity index 100%
rename from t/lib-gpg/trustdb.gpg
rename to t/t7004/trustdb.gpg
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
deleted file mode 100755
index 30401ced07..0000000000
--- a/t/t7510-signed-commit.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/sh
-
-test_description='signed commit tests'
-. ./test-lib.sh
-. "$TEST_DIRECTORY/lib-gpg.sh"
-
-test_expect_success GPG 'create signed commits' '
-	echo 1 >file && git add file &&
-	test_tick && git commit -S -m initial &&
-	git tag initial &&
-	git branch side &&
-
-	echo 2 >file && test_tick && git commit -a -S -m second &&
-	git tag second &&
-
-	git checkout side &&
-	echo 3 >elif && git add elif &&
-	test_tick && git commit -m "third on side" &&
-
-	git checkout master &&
-	test_tick && git merge -S side &&
-	git tag merge &&
-
-	echo 4 >file && test_tick && git commit -a -m "fourth unsigned" &&
-	git tag fourth-unsigned &&
-
-	test_tick && git commit --amend -S -m "fourth signed"
-'
-
-test_expect_success GPG 'show signatures' '
-	(
-		for commit in initial second merge master
-		do
-			git show --pretty=short --show-signature $commit >actual &&
-			grep "Good signature from" actual || exit 1
-			! grep "BAD signature from" actual || exit 1
-			echo $commit OK
-		done
-	) &&
-	(
-		for commit in merge^2 fourth-unsigned
-		do
-			git show --pretty=short --show-signature $commit >actual &&
-			grep "Good signature from" actual && exit 1
-			! grep "BAD signature from" actual || exit 1
-			echo $commit OK
-		done
-	)
-'
-
-test_expect_success GPG 'detect fudged signature' '
-	git cat-file commit master >raw &&
-
-	sed -e "s/fourth signed/4th forged/" raw >forged1 &&
-	git hash-object -w -t commit forged1 >forged1.commit &&
-	git show --pretty=short --show-signature $(cat forged1.commit) >actual1 &&
-	grep "BAD signature from" actual1 &&
-	! grep "Good signature from" actual1
-'
-
-test_expect_success GPG 'detect fudged signature with NUL' '
-	git cat-file commit master >raw &&
-	cat raw >forged2 &&
-	echo Qwik | tr "Q" "\000" >>forged2 &&
-	git hash-object -w -t commit forged2 >forged2.commit &&
-	git show --pretty=short --show-signature $(cat forged2.commit) >actual2 &&
-	grep "BAD signature from" actual2 &&
-	! grep "Good signature from" actual2
-'
-
-test_done
diff --git a/tag.c b/tag.c
index 3aa186df62..7d38cc0f4d 100644
--- a/tag.c
+++ b/tag.c
@@ -139,11 +139,6 @@ int parse_tag(struct tag *item)
 	return ret;
 }
 
-/*
- * Look at a signed tag object, and return the offset where
- * the embedded detached signature begins, or the end of the
- * data when there is no such signature.
- */
 size_t parse_signature(const char *buf, unsigned long size)
 {
 	char *eol;

From b9177dfc65b509ef84a6823482a97ec334f3f661 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?=
 
Date: Sun, 13 Nov 2011 17:22:15 +0700
Subject: [PATCH 2586/3720] Copy resolve_ref() return value for longer use
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

resolve_ref() may return a pointer to a static buffer. Callers that
use this value longer than a couple of statements should copy the
value to avoid some hidden resolve_ref() call that may change the
static buffer's value.

The bug found by Tony Wang  in builtin/merge.c
demonstrates this. The first call is in cmd_merge()

branch = resolve_ref("HEAD", head_sha1, 0, &flag);

Then deep in lookup_commit_or_die() a few lines after, resolve_ref()
may be called again and destroy "branch".

lookup_commit_or_die
 lookup_commit_reference
  lookup_commit_reference_gently
   parse_object
    lookup_replace_object
     do_lookup_replace_object
      prepare_replace_object
       for_each_replace_ref
        do_for_each_ref
         get_loose_refs
          get_ref_dir
           get_ref_dir
            resolve_ref

All call sites are checked and made sure that xstrdup() is called if
the value should be saved.

Signed-off-by: Nguyễn Thái Ngọc Duy 
Signed-off-by: Junio C Hamano 
---
 builtin/branch.c        |  5 +++-
 builtin/checkout.c      |  4 ++-
 builtin/commit.c        |  3 +-
 builtin/fmt-merge-msg.c |  6 +++-
 builtin/merge.c         | 62 ++++++++++++++++++++++++++---------------
 builtin/notes.c         |  6 +++-
 builtin/receive-pack.c  |  3 ++
 reflog-walk.c           |  5 +++-
 8 files changed, 66 insertions(+), 28 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0fe9c4dfe2..5b6d8393ce 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -115,8 +115,10 @@ static int branch_merged(int kind, const char *name,
 		    branch->merge[0] &&
 		    branch->merge[0]->dst &&
 		    (reference_name =
-		     resolve_ref(branch->merge[0]->dst, sha1, 1, NULL)) != NULL)
+		     resolve_ref(branch->merge[0]->dst, sha1, 1, NULL)) != NULL) {
+			reference_name = xstrdup(reference_name);
 			reference_rev = lookup_commit_reference(sha1);
+		}
 	}
 	if (!reference_rev)
 		reference_rev = head_rev;
@@ -141,6 +143,7 @@ static int branch_merged(int kind, const char *name,
 				"         '%s', even though it is merged to HEAD."),
 				name, reference_name);
 	}
+	free((char*)reference_name);
 	return merged;
 }
 
diff --git a/builtin/checkout.c b/builtin/checkout.c
index beeaee4113..c6919f1687 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -699,7 +699,9 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 	unsigned char rev[20];
 	int flag;
 	memset(&old, 0, sizeof(old));
-	old.path = xstrdup(resolve_ref("HEAD", rev, 0, &flag));
+	old.path = resolve_ref("HEAD", rev, 0, &flag);
+	if (old.path)
+		old.path = xstrdup(old.path);
 	old.commit = lookup_commit_reference_gently(rev, 1);
 	if (!(flag & REF_ISSYMREF)) {
 		free((char *)old.path);
diff --git a/builtin/commit.c b/builtin/commit.c
index c46f2d18e1..f3a6ed2bf5 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1259,7 +1259,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
 	struct commit *commit;
 	struct strbuf format = STRBUF_INIT;
 	unsigned char junk_sha1[20];
-	const char *head = resolve_ref("HEAD", junk_sha1, 0, NULL);
+	const char *head;
 	struct pretty_print_context pctx = {0};
 	struct strbuf author_ident = STRBUF_INIT;
 	struct strbuf committer_ident = STRBUF_INIT;
@@ -1304,6 +1304,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
 	rev.diffopt.break_opt = 0;
 	diff_setup_done(&rev.diffopt);
 
+	head = resolve_ref("HEAD", junk_sha1, 0, NULL);
 	printf("[%s%s ",
 		!prefixcmp(head, "refs/heads/") ?
 			head + 11 :
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 7e2f22589d..6fe9102fcc 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -268,6 +268,7 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
 		die("No current branch");
 	if (!prefixcmp(current_branch, "refs/heads/"))
 		current_branch += 11;
+	current_branch = xstrdup(current_branch);
 
 	/* get a line */
 	while (pos < in->len) {
@@ -283,8 +284,10 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
 			die ("Error in line %d: %.*s", i, len, p);
 	}
 
-	if (!srcs.nr)
+	if (!srcs.nr) {
+		free((char*)current_branch);
 		return 0;
+	}
 
 	if (merge_title)
 		do_fmt_merge_msg_title(out, current_branch);
@@ -306,6 +309,7 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
 			shortlog(origins.items[i].string, origins.items[i].util,
 					head, &rev, shortlog_len, out);
 	}
+	free((char*)current_branch);
 	return 0;
 }
 
diff --git a/builtin/merge.c b/builtin/merge.c
index 42b4f9e7bc..33be6c8a13 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1082,7 +1082,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	struct commit *head_commit;
 	struct strbuf buf = STRBUF_INIT;
 	const char *head_arg;
-	int flag, i;
+	int flag, i, ret = 0;
 	int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
 	struct commit_list *common = NULL;
 	const char *best_strategy = NULL, *wt_strategy = NULL;
@@ -1096,8 +1096,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	 * current branch.
 	 */
 	branch = resolve_ref("HEAD", head_sha1, 0, &flag);
-	if (branch && !prefixcmp(branch, "refs/heads/"))
-		branch += 11;
+	if (branch) {
+		if (!prefixcmp(branch, "refs/heads/"))
+			branch += 11;
+		branch = xstrdup(branch);
+	}
 	if (!branch || is_null_sha1(head_sha1))
 		head_commit = NULL;
 	else
@@ -1121,7 +1124,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			die(_("There is no merge to abort (MERGE_HEAD missing)."));
 
 		/* Invoke 'git reset --merge' */
-		return cmd_reset(nargc, nargv, prefix);
+		ret = cmd_reset(nargc, nargv, prefix);
+		goto done;
 	}
 
 	if (read_cache_unmerged())
@@ -1205,7 +1209,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		read_empty(remote_head->sha1, 0);
 		update_ref("initial pull", "HEAD", remote_head->sha1, NULL, 0,
 				DIE_ON_ERR);
-		return 0;
+		goto done;
 	} else {
 		struct strbuf merge_names = STRBUF_INIT;
 
@@ -1292,7 +1296,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		 * but first the most common case of merging one remote.
 		 */
 		finish_up_to_date("Already up-to-date.");
-		return 0;
+		goto done;
 	} else if (allow_fast_forward && !remoteheads->next &&
 			!common->next &&
 			!hashcmp(common->item->object.sha1, head_commit->object.sha1)) {
@@ -1313,15 +1317,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			strbuf_addstr(&msg,
 				" (no commit created; -m option ignored)");
 		o = want_commit(sha1_to_hex(remoteheads->item->object.sha1));
-		if (!o)
-			return 1;
+		if (!o) {
+			ret = 1;
+			goto done;
+		}
 
-		if (checkout_fast_forward(head_commit->object.sha1, remoteheads->item->object.sha1))
-			return 1;
+		if (checkout_fast_forward(head_commit->object.sha1,
+					  remoteheads->item->object.sha1)) {
+			ret = 1;
+			goto done;
+		}
 
 		finish(head_commit, o->sha1, msg.buf);
 		drop_save();
-		return 0;
+		goto done;
 	} else if (!remoteheads->next && common->next)
 		;
 		/*
@@ -1339,8 +1348,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			git_committer_info(IDENT_ERROR_ON_NO_NAME);
 			printf(_("Trying really trivial in-index merge...\n"));
 			if (!read_tree_trivial(common->item->object.sha1,
-					head_commit->object.sha1, remoteheads->item->object.sha1))
-				return merge_trivial(head_commit);
+					       head_commit->object.sha1,
+					       remoteheads->item->object.sha1)) {
+				ret = merge_trivial(head_commit);
+				goto done;
+			}
 			printf(_("Nope.\n"));
 		}
 	} else {
@@ -1368,7 +1380,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		}
 		if (up_to_date) {
 			finish_up_to_date("Already up-to-date. Yeeah!");
-			return 0;
+			goto done;
 		}
 	}
 
@@ -1450,9 +1462,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	 * If we have a resulting tree, that means the strategy module
 	 * auto resolved the merge cleanly.
 	 */
-	if (automerge_was_ok)
-		return finish_automerge(head_commit, common, result_tree,
-					wt_strategy);
+	if (automerge_was_ok) {
+		ret = finish_automerge(head_commit, common, result_tree,
+				       wt_strategy);
+		goto done;
+	}
 
 	/*
 	 * Pick the result from the best strategy and have the user fix
@@ -1466,7 +1480,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		else
 			fprintf(stderr, _("Merge with strategy %s failed.\n"),
 				use_strategies[0]->name);
-		return 2;
+		ret = 2;
+		goto done;
 	} else if (best_strategy == wt_strategy)
 		; /* We already have its result in the working tree. */
 	else {
@@ -1482,10 +1497,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	else
 		write_merge_state();
 
-	if (merge_was_ok) {
+	if (merge_was_ok)
 		fprintf(stderr, _("Automatic merge went well; "
 			"stopped before committing as requested\n"));
-		return 0;
-	} else
-		return suggest_conflicts(option_renormalize);
+	else
+		ret = suggest_conflicts(option_renormalize);
+
+done:
+	free((char*)branch);
+	return ret;
 }
diff --git a/builtin/notes.c b/builtin/notes.c
index f8e437db01..ccff7701fe 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -804,6 +804,7 @@ static int merge_commit(struct notes_merge_options *o)
 	struct notes_tree *t;
 	struct commit *partial;
 	struct pretty_print_context pretty_ctx;
+	int ret;
 
 	/*
 	 * Read partial merge result from .git/NOTES_MERGE_PARTIAL,
@@ -828,6 +829,7 @@ static int merge_commit(struct notes_merge_options *o)
 	o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL);
 	if (!o->local_ref)
 		die("Failed to resolve NOTES_MERGE_REF");
+	o->local_ref = xstrdup(o->local_ref);
 
 	if (notes_merge_commit(o, t, partial, sha1))
 		die("Failed to finalize notes merge");
@@ -843,7 +845,9 @@ static int merge_commit(struct notes_merge_options *o)
 
 	free_notes(t);
 	strbuf_release(&msg);
-	return merge_abort(o);
+	ret = merge_abort(o);
+	free((char*)o->local_ref);
+	return ret;
 }
 
 static int merge(int argc, const char **argv, const char *prefix)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 7ec68a1e80..d3fe42adac 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -695,7 +695,10 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
 
 	check_aliased_updates(commands);
 
+	free((char*)head_name);
 	head_name = resolve_ref("HEAD", sha1, 0, NULL);
+	if (head_name)
+		head_name = xstrdup(head_name);
 
 	for (cmd = commands; cmd; cmd = cmd->next)
 		if (!cmd->skip_update)
diff --git a/reflog-walk.c b/reflog-walk.c
index 5d81d39a52..efd13ad8ac 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -51,8 +51,11 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)
 	if (reflogs->nr == 0) {
 		unsigned char sha1[20];
 		const char *name = resolve_ref(ref, sha1, 1, NULL);
-		if (name)
+		if (name) {
+			name = xstrdup(name);
 			for_each_reflog_ent(name, read_one_reflog, reflogs);
+			free((char*)name);
+		}
 	}
 	if (reflogs->nr == 0) {
 		int len = strlen(ref);

From ada4ec627f204697a8bcbed89dc150aa3f0e51af Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Wed, 16 Nov 2011 16:54:32 -0800
Subject: [PATCH 2587/3720] refs: loosen over-strict "format" check

The add_extra_ref() interface is used to add an extra-ref that is _not_
our ref for the purpose of helping auto-following of tags and reducing
object transfer from remote repository, and they are typically formatted
as a tagname followed by ^{} to make sure no valid refs match that
pattern. In other words, these entries are deliberately formatted not to
pass check-refname-format test.

A recent series however added a test unconditionally to the add_ref()
function that is called from add_extra_ref(). The check may be sensible
for other two callsites of the add_ref() interface, but definitely is
a wrong thing to do in add_extra_ref(). Disable it.

Signed-off-by: Junio C Hamano 
---
 refs.c                     | 11 ++++++-----
 t/t5700-clone-reference.sh |  7 +++++++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/refs.c b/refs.c
index 7e6cea5458..773d81f723 100644
--- a/refs.c
+++ b/refs.c
@@ -56,7 +56,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 
 /* Add a ref_entry to the end of the ref_array (unsorted). */
 static void add_ref(const char *refname, const unsigned char *sha1,
-		    int flag, struct ref_array *refs,
+		    int flag, int check_name, struct ref_array *refs,
 		    struct ref_entry **new_entry)
 {
 	int len;
@@ -67,7 +67,8 @@ static void add_ref(const char *refname, const unsigned char *sha1,
 	entry = xmalloc(sizeof(struct ref_entry) + len);
 	hashcpy(entry->sha1, sha1);
 	hashclr(entry->peeled);
-	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
+	if (check_name &&
+	    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
 		die("Reference has invalid format: '%s'", refname);
 	memcpy(entry->name, refname, len);
 	entry->flag = flag;
@@ -257,7 +258,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 		refname = parse_ref_line(refline, sha1);
 		if (refname) {
-			add_ref(refname, sha1, flag, array, &last);
+			add_ref(refname, sha1, flag, 1, array, &last);
 			continue;
 		}
 		if (last &&
@@ -272,7 +273,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
 {
-	add_ref(refname, sha1, flag, &extra_refs, NULL);
+	add_ref(refname, sha1, flag, 0, &extra_refs, NULL);
 }
 
 void clear_extra_refs(void)
@@ -359,7 +360,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
 					hashclr(sha1);
 					flag |= REF_BROKEN;
 				}
-			add_ref(ref, sha1, flag, array, NULL);
+			add_ref(ref, sha1, flag, 1, array, NULL);
 		}
 		free(ref);
 		closedir(dir);
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index 895f5595ae..c4c375ac04 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -146,4 +146,11 @@ test_expect_success 'cloning with reference being subset of source (-l -s)' \
 
 cd "$base_dir"
 
+test_expect_success 'clone with reference from a tagged repository' '
+	(
+		cd A && git tag -a -m 'tagged' HEAD
+	) &&
+	git clone --reference=A A I
+'
+
 test_done

From 37817ba08681c085d383238b13000d37ad3dd93d Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Wed, 16 Nov 2011 16:54:32 -0800
Subject: [PATCH 2588/3720] refs: loosen over-strict "format" check

The add_extra_ref() interface is used to add an extra-ref that is _not_
our ref for the purpose of helping auto-following of tags and reducing
object transfer from remote repository, and they are typically formatted
as a tagname followed by ^{} to make sure no valid refs match that
pattern. In other words, these entries are deliberately formatted not to
pass check-refname-format test.

A recent series however added a test unconditionally to the add_ref()
function that is called from add_extra_ref(). The check may be sensible
for other two callsites of the add_ref() interface, but definitely is
a wrong thing to do in add_extra_ref(). Disable it.

Signed-off-by: Junio C Hamano 
---
 refs.c                     | 12 +++++++-----
 t/t5700-clone-reference.sh |  7 +++++++
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/refs.c b/refs.c
index 59f1db2952..739b226ff3 100644
--- a/refs.c
+++ b/refs.c
@@ -58,12 +58,14 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 }
 
 static struct ref_entry *create_ref_entry(const char *refname,
-					  const unsigned char *sha1, int flag)
+					  const unsigned char *sha1, int flag,
+					  int check_name)
 {
 	int len;
 	struct ref_entry *ref;
 
-	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
+	if (check_name &&
+	    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
 		die("Reference has invalid format: '%s'", refname);
 	len = strlen(refname) + 1;
 	ref = xmalloc(sizeof(struct ref_entry) + len);
@@ -261,7 +263,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 		refname = parse_ref_line(refline, sha1);
 		if (refname) {
-			last = create_ref_entry(refname, sha1, flag);
+			last = create_ref_entry(refname, sha1, flag, 1);
 			add_ref(array, last);
 			continue;
 		}
@@ -277,7 +279,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
 {
-	add_ref(&extra_refs, create_ref_entry(refname, sha1, flag));
+	add_ref(&extra_refs, create_ref_entry(refname, sha1, flag, 0));
 }
 
 void clear_extra_refs(void)
@@ -364,7 +366,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
 					hashclr(sha1);
 					flag |= REF_BROKEN;
 				}
-			add_ref(array, create_ref_entry(refname, sha1, flag));
+			add_ref(array, create_ref_entry(refname, sha1, flag, 1));
 		}
 		free(refname);
 		closedir(dir);
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index 895f5595ae..c4c375ac04 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -146,4 +146,11 @@ test_expect_success 'cloning with reference being subset of source (-l -s)' \
 
 cd "$base_dir"
 
+test_expect_success 'clone with reference from a tagged repository' '
+	(
+		cd A && git tag -a -m 'tagged' HEAD
+	) &&
+	git clone --reference=A A I
+'
+
 test_done

From 99df39b20a4c18ef89f4bbdb74f75417ac704c5c Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 2589/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 483ef5cfde..63db54a0ba 100644
--- a/Makefile
+++ b/Makefile
@@ -1201,7 +1201,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From 43adf7bb24b363fc68852b490150eb0257e11c5b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 2590/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 63db54a0ba..233d3fef1a 100644
--- a/Makefile
+++ b/Makefile
@@ -1138,16 +1138,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 5385c5002ec4335c5e564031ae0b3ee9d59b0fa7 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2591/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index fecf0d0776..66c289803c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From b5c6744960434e9532af403d4d0ce179850d6d85 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2592/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 8a7d2d4cb1..a248045b53 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -155,6 +155,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index d07554c884..5fbed38637 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index afad7ea3aa..634e139da7 100644
--- a/cache.h
+++ b/cache.h
@@ -602,6 +602,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index efdc703257..fc7f424483 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 66c289803c..0f776c872a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -324,6 +321,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index 5ea101fb25..f9bcbed2b6 100644
--- a/config.c
+++ b/config.c
@@ -686,6 +686,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 2c41d7d6cb..4cc125d2af 100644
--- a/environment.c
+++ b/environment.c
@@ -62,6 +62,7 @@ int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 77062ed2a6..46b1feadef 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -576,4 +576,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 23ce6106c0549f56f6fd3b1725babb13001a953b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2593/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index fc7f424483..3d7ce02e85 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 95d9ebe36d8ef5c161c8078b9c022c30b3eba7a1 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2594/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 8ec1dd083e287ee6e2b01c53a3bdfd6861b90369 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2595/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index f8971603f7..7d16b08ae3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1270,9 +1270,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2080,7 +2077,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2092,12 +2089,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2118,18 +2122,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2150,20 +2151,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 169e52df724d704be07a80706e1dacffba049181 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2596/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 7d16b08ae3..94130179b7 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 5efcde00d759373a9b5efbef2e00634a5579c235 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2597/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 4cde0c493b..6b18e34726 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9480,7 +9480,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 320c80237dee3d22256d9b71ce4a05339cdb4601 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2598/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 555f6c239854c6adc627ef2be5f22d08298187f9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2599/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 11da27fa7cc055291facaa36d2abee397a88d5d5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2600/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index a248045b53..829ac10f78 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1674,6 +1674,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d3fe42adac..d4c1ef5789 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -87,7 +89,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -391,6 +398,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -422,6 +467,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -450,6 +502,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 9b700e3804a5e5c6e863a595c9ece5e3a8668704 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2601/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d491db92c9..d1f09be986 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 26f67da3618a443c77d4caa3957f5f94dd2b7ac1 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2602/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d1f09be986..fd283e2625 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 21016395c49dc36f2ced6bd8b660d99753087085 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2603/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 0315ad76f8..fc2fb38117 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 3d7ce02e85..68d5c694bd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 0f776c872a..f81f326272 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -355,3 +355,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index f9bcbed2b6..3babe1db9b 100644
--- a/config.c
+++ b/config.c
@@ -893,7 +893,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 46b1feadef..ae36614cbd 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -580,4 +580,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From ed8552c831e8df535244f39e31cc8d3c9d0bf284 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2604/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From a8202e4c87a6e664079aa715748b3f82746c15f6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2605/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 9042432e23..3ed18a1886 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -557,7 +557,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -726,7 +727,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -802,7 +804,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -826,7 +828,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From 4f1f7bad07cf30a6d47f9b06428129518f8dbe9b Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2606/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index bdd9513b84..eadb24c867 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From ec291143c15053328a5f3a47cdf2c6e758f2d7a6 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2607/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 634e139da7..86359e8265 100644
--- a/cache.h
+++ b/cache.h
@@ -773,7 +773,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 68d5c694bd..e707f68b44 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index f81f326272..9b3eebdeb9 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -315,6 +315,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index ae36614cbd..0f69decaae 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -210,6 +210,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 65754ac3eaa963299dc98d225f0aa63a59df52ff Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2608/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index fc2fb38117..ab0602458a 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From bfa895be7491f7cd1285b429daf58ad6ea05e722 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2609/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e707f68b44..e8c8bd5513 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 91527ef08524a02fd49817e8c7e8e77d118bd9c3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2610/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 94130179b7..6b72b9ef9b 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1178,6 +1178,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From cf9fe978e035ae10cc89e003a57a890050e9c6aa Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2611/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6b18e34726..2a92e20f06 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -369,7 +369,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9480,18 +9480,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9502,6 +9491,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 0c94a585a8845fcf154c2c26750e858f8cf2a234 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2612/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index e8c8bd5513..8cb35b693f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 6adfe5c463157dfd7b27a7e9fe640deec0ab038d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2613/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9b3eebdeb9..4b3883f39e 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -296,9 +296,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From e075d7292632bd718475b5803d800dc4220da4b6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2614/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 2ab0c308e1013d9f1eb9ebfe77d12cd3fdaddd5e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2615/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From a62962451b929e6d27b4483f07403d8511359617 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2616/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index e7694a3a4c..29222b3fbf 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -549,7 +549,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 85973622509e035ecb6259ff9e1beec6de56ac72 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2617/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 4f0c3bd90c..f12ba0bb15 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,6 +4274,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From c53d57626af1c873e5928c509b915f07768a4fa6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2618/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f12ba0bb15..e23052209e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4289,7 +4289,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 04201f516fb28c7bfd3b48b7eea4aa3b178e71d1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2619/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 44fcc4d178..f3b2c90cdd 100644
--- a/http.c
+++ b/http.c
@@ -3,6 +3,7 @@
 #include "sideband.h"
 #include "run-command.h"
 #include "url.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -157,6 +158,18 @@ static char *git_getpass_with_description(const char *what, const char *desc)
 	return xstrdup(r);
 }
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -164,17 +177,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 9aadc4efea1593be96df9ff5dbcf9f2db911245a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2620/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index c59b0c98fe..68fd050e94 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -279,6 +279,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From 67cd09d307f4d1efdd1d4b9098954f2175503c87 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2621/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d4c1ef5789..45289d98e9 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -401,7 +401,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 09572e919d59f3f9c4428c0a3f1e2608479cc70a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2622/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 988ea1d332..133c4583b7 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "dir.h"
 #include "thread-utils.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -206,6 +207,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -216,6 +233,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -529,6 +549,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -995,6 +1018,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 194c6a340678320817686dc284894c31d98e788d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2623/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index ed8232075e..a17e0a1719 100644
--- a/Makefile
+++ b/Makefile
@@ -280,7 +280,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From fefe3c81c6c1eade6f122394e412ee0da82ab728 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2624/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8cb35b693f..2106ce5f78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, unsigned options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From d0f60ea3cc57775c719b6dae6bd99201cc618392 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2625/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index a17e0a1719..acc212c975 100644
--- a/Makefile
+++ b/Makefile
@@ -1963,7 +1963,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2003,6 +2003,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 41d63e5f5d8d784985e2b61d421931eae0da9718 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2626/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 63849836c8..2ef2ec912e 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 67810883416defb6afbaecac587e3beab97a91c2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2627/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 133c4583b7..63b00f8fab 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1083,6 +1083,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From 88d647413ec52c3ccb44788001b64cf0a195ac0d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2628/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 63b00f8fab..b18491bc8c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1083,7 +1083,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From 8ba705fee128241d00be758ac418ae4325dc8745 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2629/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From cfc0df37a2ac281327d24f52e0a8dad117a7232e Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2630/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2106ce5f78..bf9e01fb1a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 6a1509bfee78a4754b3c50e8ebbb8c1317228adf Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2631/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 7d2098e3f7bb6358f1d38419430cdd63e23102cc Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2632/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From 2edc4b607facc1222e5d3eba4ddda93eff3ab879 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2633/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2634/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93635..73f41482a8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2635/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 54a4a3e0f0bd05602c4a0efc7afd84cb54b1c1e6 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2636/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2637/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 4b3883f39e..0492b9c30f 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 41fef50591b4e5063de56af6067404ce3f51bca4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2638/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index acc212c975..9d6f6d6132 100644
--- a/Makefile
+++ b/Makefile
@@ -1133,6 +1133,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1225,6 +1226,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 35e71876e288429aa98d3d74ccdf8ca01deba84e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2639/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 00b55df68dcdce7e00915f3b921c9f090669d2a3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2640/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From 07b844cc8e4b45a04dfc9deeef8bc1480b36ef55 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2641/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 138a01b68c7bed7082c6c7816be307614f0eef32 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2642/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 9add71ee0e33f3e2f07314cebf7b87c823bafec7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2643/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bf9e01fb1a..87c8a2c0e1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From ce2c91d27c00737018d51aedb303252cd43d30d0 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2644/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 87c8a2c0e1..509103b676 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 0492b9c30f..c5d9a79303 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 83687b8d4dc8681d85ac9d1409e7563740c927ff Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2645/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 509103b676..370cf8885c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 1844f66eed4b91c3715b556073532075ace3de73 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2646/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e23052209e..305a5834e5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6468,7 +6468,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6516,6 +6528,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From cd871e2f1cc0939ac7072195b10b59b5e5d2397a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2647/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 305a5834e5..de07d2d566 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4274,7 +4274,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 997df833981a19fd5aeff0be42b32f59d765a265 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2648/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index de07d2d566..f1ebf7edf1 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6581,7 +6581,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 91771c63739fbb3a82def24e280472852f8d7354 Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2649/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 370cf8885c..9aba372fa5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 168e9311200680dcd375048ba60ab17da8d638ed Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2650/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index c5d9a79303..3d99c03b71 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From c26caa0faea8d3dcb9301ccf2ceadd9f36f245af Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2651/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index d8b64d7a67..50f4855117 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -109,7 +110,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -274,7 +280,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From d21011e26a130cfdb786b1a22c36dcdc2ba03d4d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2652/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 829ac10f78..647c95b2f5 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -685,6 +685,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index 50f4855117..eec078300c 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From f087f96e6977fba7aa0e23b715769f9f21208967 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 2653/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 3d99c03b71..2c70a275b4 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 0f69decaae..1023121215 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From 1bf307a11aab9405b4e9d479ed7f9fc7bce3b153 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 2654/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From f6ecc9eacf3ef007f8d818545e5ff6a6c913e736 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 2655/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 9d6f6d6132..08be7d58aa 100644
--- a/Makefile
+++ b/Makefile
@@ -1131,6 +1131,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From e40ae218b5ac38d374857419894835546ff87680 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 2656/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From c13a9caa4407416578072b5f5dea100051f3d6c3 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 2657/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 08be7d58aa..651cf300d8 100644
--- a/Makefile
+++ b/Makefile
@@ -1208,7 +1208,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From cbfea488960e81f8f63fdb23efdfffb5cfd495a6 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 16:50:50 +0000
Subject: [PATCH 2658/3720] gitk: fix the display of files when filtered by
 path

Launching 'gitk -- .' or 'gitk -- ..\t' restricts the display to files
under the given directory but the file list is left empty. This is because
the path_filter function fails to match the filenames which are relative
to the working tree to the filter which is filessytem relative.
This solves the problem by making both names fully qualified filesystem
paths before performing the comparison.

Signed-off-by: Pat Thoyts 
Tested-by: David Aguilar 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 2a92e20f06..b728345c4c 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -18,6 +18,26 @@ proc gitdir {} {
     }
 }
 
+proc gitworktree {} {
+    variable _gitworktree
+    if {[info exists _gitworktree]} {
+	return $_gitworktree
+    }
+    # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+    if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+        # try to set work tree from environment, core.worktree or use
+        # cdup to obtain a relative path to the top of the worktree. If
+        # run from the top, the ./ prefix ensures normalize expands pwd.
+        if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+	    catch {set _gitworktree [exec git config --get core.worktree]}
+	    if {$_gitworktree eq ""} {
+		set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+	    }
+        }
+    }
+    return $_gitworktree
+}
+
 # A simple scheduler for compute-intensive stuff.
 # The aim is to make sure that event handlers for GUI actions can
 # run at least every 50-100 ms.  Unfortunately fileevent handlers are
@@ -7376,19 +7396,15 @@ proc startdiff {ids} {
     }
 }
 
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
 proc path_filter {filter name} {
+    set worktree [gitworktree]
     foreach p $filter {
-	set l [string length $p]
-	if {[string index $p end] eq "/"} {
-	    if {[string compare -length $l $p $name] == 0} {
-		return 1
-	    }
-	} else {
-	    if {[string compare -length $l $p $name] == 0 &&
-		([string length $name] == $l ||
-		 [string index $name $l] eq "/")} {
-		return 1
-	    }
+	set fq_p [file normalize $p]
+	set fq_n [file normalize [file join $worktree $name]]
+	if {[string match [file normalize $fq_p]* $fq_n]} {
+	    return 1
 	}
     }
     return 0

From a4ad8cda8c3c68c40c22b0ef118fa03b58a17d7d Mon Sep 17 00:00:00 2001
From: Sven Strickroth 
Date: Wed, 28 Dec 2011 01:11:31 +0100
Subject: [PATCH 2659/3720] perl/Git.pm: "prompt" helper to honor GIT_ASKPASS
 and SSH_ASKPASS
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

git-svn reads passwords from an interactive terminal or by using
GIT_ASKPASS helper tool. But if GIT_ASKPASS environment variable is not
set, git-svn does not try to use SSH_ASKPASS as git-core does. This
cause GUIs (w/o STDIN connected) to hang waiting forever for git-svn to
complete (http://code.google.com/p/tortoisegit/issues/detail?id=967).

Earlier, 56a853b (git-svn: Support retrieving passwords with GIT_ASKPASS,
2010-03-02) tried to solve this issue, but was incomplete as described
above.

Instead of using hand-rolled prompt-response code that only works with the
interactive terminal and uses GIT_ASKPASS, introduce prompt() helper
function in Git.pm library that also pays attention to SSH_ASKPASS as a
fallback, and use it in git-svn. The result mimics the behaviour of the
core git better.

Signed-off-by: Sven Strickroth 
Helped-by: Ævar Arnfjörð Bjarmason
Signed-off-by: Junio C Hamano 
---
 git-svn.perl | 20 +-------------------
 perl/Git.pm  | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 51 insertions(+), 20 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index e30df22d89..6a0117640d 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -4415,25 +4415,7 @@ sub username {
 
 sub _read_password {
 	my ($prompt, $realm) = @_;
-	my $password = '';
-	if (exists $ENV{GIT_ASKPASS}) {
-		open(PH, "-|", $ENV{GIT_ASKPASS}, $prompt);
-		$password = ;
-		$password =~ s/[\012\015]//; # \n\r
-		close(PH);
-	} else {
-		print STDERR $prompt;
-		STDERR->flush;
-		require Term::ReadKey;
-		Term::ReadKey::ReadMode('noecho');
-		while (defined(my $key = Term::ReadKey::ReadKey(0))) {
-			last if $key =~ /[\012\015]/; # \n\r
-			$password .= $key;
-		}
-		Term::ReadKey::ReadMode('restore');
-		print STDERR "\n";
-		STDERR->flush;
-	}
+	my $password = Git::prompt($prompt);
 	$password;
 }
 
diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..46f11a89de 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -58,7 +58,7 @@ require Exporter;
                 command_output_pipe command_input_pipe command_close_pipe
                 command_bidi_pipe command_close_bidi_pipe
                 version exec_path html_path hash_object git_cmd_try
-                remote_refs
+                remote_refs prompt
                 temp_acquire temp_release temp_reset temp_path);
 
 
@@ -512,6 +512,55 @@ C). Useful mostly only internally.
 sub html_path { command_oneline('--html-path') }
 
 
+=item prompt ( PROMPT )
+
+Query user C and return answer from user.
+
+If an external helper is specified via GIT_ASKPASS or SSH_ASKPASS, it
+is used to interact with the user; otherwise the prompt is given to
+and the answer is read from the terminal.
+
+=cut
+
+sub prompt {
+	my ($prompt) = @_;
+	my $ret;
+	if (!defined $ret) {
+		$ret = _prompt($ENV{'GIT_ASKPASS'}, $prompt);
+	}
+	if (!defined $ret) {
+		$ret = _prompt($ENV{'SSH_ASKPASS'}, $prompt);
+	}
+	if (!defined $ret) {
+		$ret = '';
+		print STDERR $prompt;
+		STDERR->flush;
+		require Term::ReadKey;
+		Term::ReadKey::ReadMode('noecho');
+		while (defined(my $key = Term::ReadKey::ReadKey(0))) {
+			last if $key =~ /[\012\015]/; # \n\r
+			$ret .= $key;
+		}
+		Term::ReadKey::ReadMode('restore');
+		print STDERR "\n";
+		STDERR->flush;
+	}
+	return $ret;
+}
+
+sub _prompt {
+	my ($askpass, $prompt) = @_;
+	return unless ($askpass);
+
+	open my $fh, "-|", $askpass, $prompt
+		or return;
+	my $ret = <$fh>;
+	$ret =~ s/[\012\015]//g; # \n\r
+	close ($fh);
+	return $ret;
+}
+
+
 =item repo_path ()
 
 Return path to the git repository. Must be called on a repository instance.

From 3072037b14d5127bd418d37b69ebcef878658e05 Mon Sep 17 00:00:00 2001
From: Clemens Buchacher 
Date: Wed, 4 Jan 2012 16:55:35 +0100
Subject: [PATCH 2660/3720] daemon: add tests

The semantics of the git daemon tests are similar to the http transport
tests.  In fact, they are only a slightly modified copy of t5550, plus the
newly added remote error tests.

All git-daemon tests will be skipped unless the environment variable
GIT_TEST_GIT_DAEMON is set.

Signed-off-by: Clemens Buchacher 
Helped-by: Jeff King 
Signed-off-by: Junio C Hamano 
---
 t/lib-git-daemon.sh   |  56 ++++++++++++++++
 t/t5570-git-daemon.sh | 148 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 204 insertions(+)
 create mode 100644 t/lib-git-daemon.sh
 create mode 100755 t/t5570-git-daemon.sh

diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh
new file mode 100644
index 0000000000..c0ff9e2b65
--- /dev/null
+++ b/t/lib-git-daemon.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+if test -z "$GIT_TEST_GIT_DAEMON"
+then
+	skip_all="git-daemon testing disabled (define GIT_TEST_GIT_DAEMON to enable)"
+	test_done
+fi
+
+LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-'8121'}
+
+GIT_DAEMON_PID=
+GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo
+GIT_DAEMON_URL=git://127.0.0.1:$LIB_GIT_DAEMON_PORT
+
+start_git_daemon() {
+	if test -n "$GIT_DAEMON_PID"
+	then
+		error "start_git_daemon already called"
+	fi
+
+	mkdir -p "$GIT_DAEMON_DOCUMENT_ROOT_PATH"
+
+	trap 'code=$?; stop_git_daemon; (exit $code); die' EXIT
+
+	say >&3 "Starting git daemon ..."
+	git daemon --listen=127.0.0.1 --port="$LIB_GIT_DAEMON_PORT" \
+		--reuseaddr --verbose \
+		--base-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH" \
+		"$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \
+		>&3 2>&4 &
+	GIT_DAEMON_PID=$!
+}
+
+stop_git_daemon() {
+	if test -z "$GIT_DAEMON_PID"
+	then
+		return
+	fi
+
+	trap 'die' EXIT
+
+	# kill git-daemon child of git
+	say >&3 "Stopping git daemon ..."
+	pkill -P "$GIT_DAEMON_PID"
+	wait "$GIT_DAEMON_PID"
+	ret=$?
+	#
+	# We signal TERM=15 to the child and expect the parent to
+	# exit with 143 = 128+15.
+	#
+	if test $ret -ne 143
+	then
+		error "git daemon exited with status: $ret"
+	fi
+	GIT_DAEMON_PID=
+}
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
new file mode 100755
index 0000000000..7cbc9994a3
--- /dev/null
+++ b/t/t5570-git-daemon.sh
@@ -0,0 +1,148 @@
+#!/bin/sh
+
+test_description='test fetching over git protocol'
+. ./test-lib.sh
+
+LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570}
+. "$TEST_DIRECTORY"/lib-git-daemon.sh
+start_git_daemon
+
+test_expect_success 'setup repository' '
+	echo content >file &&
+	git add file &&
+	git commit -m one
+'
+
+test_expect_success 'create git-accessible bare repository' '
+	mkdir "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
+	(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
+	 git --bare init &&
+	 : >git-daemon-export-ok
+	) &&
+	git remote add public "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
+	git push public master:master
+'
+
+test_expect_success 'clone git repository' '
+	git clone "$GIT_DAEMON_URL/repo.git" clone &&
+	test_cmp file clone/file
+'
+
+test_expect_success 'fetch changes via git protocol' '
+	echo content >>file &&
+	git commit -a -m two &&
+	git push public &&
+	(cd clone && git pull) &&
+	test_cmp file clone/file
+'
+
+test_expect_failure 'remote detects correct HEAD' '
+	git push public master:other &&
+	(cd clone &&
+	 git remote set-head -d origin &&
+	 git remote set-head -a origin &&
+	 git symbolic-ref refs/remotes/origin/HEAD > output &&
+	 echo refs/remotes/origin/master > expect &&
+	 test_cmp expect output
+	)
+'
+
+test_expect_success 'prepare pack objects' '
+	cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git &&
+	(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git &&
+	 git --bare repack -a -d
+	)
+'
+
+test_expect_success 'fetch notices corrupt pack' '
+	cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
+	(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
+	 p=`ls objects/pack/pack-*.pack` &&
+	 chmod u+w $p &&
+	 printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
+	) &&
+	mkdir repo_bad1.git &&
+	(cd repo_bad1.git &&
+	 git --bare init &&
+	 test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad1.git" &&
+	 test 0 = `ls objects/pack/pack-*.pack | wc -l`
+	)
+'
+
+test_expect_success 'fetch notices corrupt idx' '
+	cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
+	(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
+	 p=`ls objects/pack/pack-*.idx` &&
+	 chmod u+w $p &&
+	 printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
+	) &&
+	mkdir repo_bad2.git &&
+	(cd repo_bad2.git &&
+	 git --bare init &&
+	 test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad2.git" &&
+	 test 0 = `ls objects/pack | wc -l`
+	)
+'
+
+test_remote_error()
+{
+	do_export=YesPlease
+	while test $# -gt 0
+	do
+		case $1 in
+		-x)
+			shift
+			chmod -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
+			;;
+		-n)
+			shift
+			do_export=
+			;;
+		*)
+			break
+		esac
+	done
+
+	if test $# -ne 3
+	then
+		error "invalid number of arguments"
+	fi
+
+	cmd=$1
+	repo=$2
+	msg=$3
+
+	if test -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo"
+	then
+		if test -n "$do_export"
+		then
+			: >"$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok"
+		else
+			rm -f "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok"
+		fi
+	fi
+
+	test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" 2>output &&
+	echo "fatal: remote error: $msg: /$repo" >expect &&
+	test_cmp expect output
+	ret=$?
+	chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
+	(exit $ret)
+}
+
+msg="access denied or repository not exported"
+test_expect_success 'clone non-existent' "test_remote_error    clone nowhere.git '$msg'"
+test_expect_success 'push disabled'      "test_remote_error    push  repo.git    '$msg'"
+test_expect_success 'read access denied' "test_remote_error -x fetch repo.git    '$msg'"
+test_expect_success 'not exported'       "test_remote_error -n fetch repo.git    '$msg'"
+
+stop_git_daemon
+start_git_daemon --informative-errors
+
+test_expect_success 'clone non-existent' "test_remote_error    clone nowhere.git 'no such repository'"
+test_expect_success 'push disabled'      "test_remote_error    push  repo.git    'service not enabled'"
+test_expect_success 'read access denied' "test_remote_error -x fetch repo.git    'no such repository'"
+test_expect_success 'not exported'       "test_remote_error -n fetch repo.git    'repository not exported'"
+
+stop_git_daemon
+test_done

From 99dadea643fb6c7df994776f6d5930c88e5a94ad Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 2661/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index a782409306..79e575eac8 100644
--- a/Makefile
+++ b/Makefile
@@ -1181,16 +1181,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 963d157b6508111503b6c289db3db488e7eb3565 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2662/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..57d5f59ca8 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 782af6a736b63a6bc0178f8719522b8b6ce46a22 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2663/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 68cf70242e..0376936f11 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -152,6 +152,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 10afd71d43..bbc9a8cafa 100644
--- a/cache.h
+++ b/cache.h
@@ -604,6 +604,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..cc1b34999d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 57d5f59ca8..4acdac969d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -324,6 +321,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index 40f9c6d103..b6dcfa8f2e 100644
--- a/config.c
+++ b/config.c
@@ -686,6 +686,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index c93b8f44df..bf6f0c29ed 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 8f3972cd32..11d68b1104 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -577,4 +577,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 129a74eaa1038a394971d80f9e883ba3fa1f2a0e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2664/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index cc1b34999d..665f6abc40 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From d1e90bb92a70794ed037b6df07f62183f5e74c3e Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2665/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 54d11875d6bab5ec1e3422bcf442fcaf47d536e1 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2666/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From bb401600dc886f5976074908b7716d8fca0bbc98 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2667/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From baaa7d1b0aa6808b068d2d7555c586dc454f3e45 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2668/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 64ef3c4013..e2cda370fa 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9499,7 +9499,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From a5fa3deade914becb56ca72de3cb263e84378013 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2669/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 0603d40aae04b9e863c95bb2203b830f66000c90 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2670/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 660213cd22de8532eb9072494abf19b7294e142e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2671/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0376936f11..b1fa92756c 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1705,6 +1705,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d2dcb7e4af..88083168f8 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -88,7 +90,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -392,6 +399,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -423,6 +468,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -451,6 +503,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 8698399ead7ec58d59b431c3192ad18ca105490c Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2672/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d491db92c9..d1f09be986 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From bdc196ae9ef59c40c486443319f9affee2e1799a Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2673/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d1f09be986..fd283e2625 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 2930ac0ab542770b3809642e2413ad9c72313da9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2674/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index d35c06ae51..723703464f 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 665f6abc40..e5f1c36995 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 4acdac969d..4285272452 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -355,3 +355,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index b6dcfa8f2e..298bbcf2e5 100644
--- a/config.c
+++ b/config.c
@@ -897,7 +897,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 11d68b1104..4f9186559a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -581,4 +581,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 35315941865f52f058e224f668717f2ccd6b4294 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2675/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From 0046fc3a4512e37d61b3e0a7f4fd63c964944ac0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2676/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 1c13b13991..8fbd2f8cff 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -556,7 +556,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -719,7 +720,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -795,7 +797,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -819,7 +821,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From af3871f53004850aa387330897eccc4bc2a2618e Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2677/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index a65dfc7ea9..de0a5d5fd8 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 7882835308fe814f855e7b003721f8cc9752cd94 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2678/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index bbc9a8cafa..0a6962f06c 100644
--- a/cache.h
+++ b/cache.h
@@ -757,7 +757,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index e5f1c36995..39ce7b446d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 4285272452..74f7c6d247 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -315,6 +315,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 4f9186559a..1827cc797b 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 9af05b2654bb57b7dcdf45efc4e9594c834fd6fb Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2679/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index 723703464f..ffa3ff26ac 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From 5edbf383645fde9de70c39424f828686b109e63f Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2680/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 39ce7b446d..71adbc497a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 90e66c1c20355af8cb480c86e5d2930a4a994e70 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2681/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From a1d0343c082070878151d6b95b5a50a8c55ec5f8 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2682/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index e2cda370fa..928a25d904 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -365,7 +365,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9499,18 +9499,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9521,6 +9510,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From c451720c9cff7775000b6ec30e733d6f823b2a59 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2683/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 71adbc497a..fe3cae3a38 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From c0b3607fee4b141d480eb86916fc05aa646ca4d9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2684/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 74f7c6d247..9af6580651 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -296,9 +296,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 8cc5f0bc24ea1e9f570ce4686652cb4060243942 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2685/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 2ee51f6c7ee909e71c4f83d04c3fb00673508e4b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2686/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From c29d64de043cc1c6eef58e346ba62cbe1492fcec Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2687/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index 5cac6bfcd4..570908d632 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -588,7 +588,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 6f8b531a8a1d4703b3395bfad014b1f0f2d4a37c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2688/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index fc41b07bcb..0a130947fd 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4302,6 +4302,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From d80a6bffe41fab648a02ba7216833845a0f700f7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2689/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 0a130947fd..38a6df80a6 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4317,7 +4317,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From ca233ad2a54a6a67e0d46fba2b935452cd92b3e3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2690/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 0ffd79cd81..3f3e3e72fd 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -138,6 +139,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 9fe26d5ac6d016ae7207d0b5c56939a6e3e24b0e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2691/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index 1c42900ff8..b79336d712 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -280,6 +280,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From c410c9de676b11bb4438e69812f1aaa0eeb45ea4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2692/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 88083168f8..d33dee1862 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -402,7 +402,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From d890c9f859d587b03c75a0a5fc1f7db963fd032a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2693/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 9ce064ac11..3589067dcc 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -205,6 +206,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -215,6 +232,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -530,6 +550,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -996,6 +1019,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 8a088841de766247411aaa8108b5f5587e0192b1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2694/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 79e575eac8..7fa04aad10 100644
--- a/Makefile
+++ b/Makefile
@@ -301,7 +301,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From fa93076743cd989f5ff37b7a2ba064e75feb794d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2695/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index fe3cae3a38..f86800680c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 7bb102010e9930e6008b7ff76496f887b714138a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2696/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 7fa04aad10..3a4fb25885 100644
--- a/Makefile
+++ b/Makefile
@@ -2035,7 +2035,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2075,6 +2075,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 538ba9a8a4468e69fdab1b945c6c55a60e122557 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2697/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..18a93cba9f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From a2ec7371865d8beccb9aaefac3a8695e2489af88 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2698/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 3589067dcc..35df5f540c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1088,6 +1088,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From 3c812f378753dd07a767805534864ddbb518994c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2699/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 35df5f540c..86af33e34a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1088,7 +1088,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From 3e1598355a8947a3018214ca28a625b63cc67e21 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2700/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From f2cdbc27d78dfbce6622c2583a3eaed530ac32fe Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2701/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f86800680c..61a1230433 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 32dc5c07fa61330e3ecf5c0bd5b1ec582d3024b9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2702/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 7a2ed2f815d6207a71952a15408c4c8a85b20509 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2703/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From 095f469a8115e50c289121acedb0e7c83ab1aa4f Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2704/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2705/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93635..73f41482a8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2706/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 1fe22fec0328bae88fe6aa5d1a8066852185248b Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2707/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2708/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9af6580651..60e281a7fe 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From bc0687f097103d497b1617e154e384a9ede73d89 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2709/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3a4fb25885..956a7831e6 100644
--- a/Makefile
+++ b/Makefile
@@ -1175,6 +1175,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1268,6 +1269,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 1467d21f118558d6953b52fb1e1379c5626381c9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2710/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From f435c6d7bf78d3826fe75cb0a737de3b7a455b1c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2711/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From 7f25504d5738e57921eff4b95fe39ff9acadb932 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2712/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 19daf8ca16ae80ae330ca549a3fc7dcb33fb8b6f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2713/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 3e8dcb6a78bf327ccb0687ff04b8461001ecf8e6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2714/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 61a1230433..398c11f175 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 520e5103af44243f122a25bf45df7aa4a8df265a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2715/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 398c11f175..8565118abd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 60e281a7fe..da9c53583a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From e3ec29fdc5d245fe003c2df1ee87660950615e60 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2716/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8565118abd..1b40ff2373 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 8c06d836f026c87d3937eec206104be913ef1839 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2717/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 38a6df80a6..7d72feb40f 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6607,7 +6607,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6655,6 +6667,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 254ecded9511c39d0ce18a499452b84955966dd5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2718/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 7d72feb40f..19a5bb7651 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4302,7 +4302,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From dfa1f88a13ddaaef288fecbbc03baa2adea453b3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2719/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 19a5bb7651..61e896168e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6720,7 +6720,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 0a57ef24eebd435e7f121b92b256085de7f7bb61 Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2720/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1b40ff2373..952a2a6819 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 482db7827307b6b12ac9c2175a3e863c35946ff3 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2721/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index da9c53583a..1f9f35f63d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From be4653ed72c73983ce346612d1484aa1a3f6711d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2722/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index d8b64d7a67..50f4855117 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -109,7 +110,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -274,7 +280,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From e4c343fa1cdcbc0a61206310ccbb4badd84ce427 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2723/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index b1fa92756c..225e34673a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -682,6 +682,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index 50f4855117..eec078300c 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 08277cbc0014e6475a18feaaa15105558b2877ad Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 2724/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1f9f35f63d..407bad231b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 1827cc797b..e465862ea4 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From e4ce1bbe46cd2020cf28a63dcb12200bb2ea4977 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 2725/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From 5dedcc3c98e95d9537916db604e8ce62aaf09227 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 2726/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 956a7831e6..052f285cda 100644
--- a/Makefile
+++ b/Makefile
@@ -1173,6 +1173,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From 617b6240c0b16a96b1b4a72cb3699a946b0246ed Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 2727/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From 7d27baac407de0877be0da49faba927b0e1e385f Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 2728/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 052f285cda..f545ce34c5 100644
--- a/Makefile
+++ b/Makefile
@@ -1251,7 +1251,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From 3fab96ace63ecdd616ca6a3a202c0b525002809b Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 16:50:50 +0000
Subject: [PATCH 2729/3720] gitk: fix the display of files when filtered by
 path

Launching 'gitk -- .' or 'gitk -- ..\t' restricts the display to files
under the given directory but the file list is left empty. This is because
the path_filter function fails to match the filenames which are relative
to the working tree to the filter which is filessytem relative.
This solves the problem by making both names fully qualified filesystem
paths before performing the comparison.

Signed-off-by: Pat Thoyts 
Tested-by: David Aguilar 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 928a25d904..77c38b01b6 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -14,6 +14,26 @@ proc hasworktree {} {
 		  [exec git rev-parse --is-inside-git-dir] == "false"}]
 }
 
+proc gitworktree {} {
+    variable _gitworktree
+    if {[info exists _gitworktree]} {
+	return $_gitworktree
+    }
+    # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+    if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+        # try to set work tree from environment, core.worktree or use
+        # cdup to obtain a relative path to the top of the worktree. If
+        # run from the top, the ./ prefix ensures normalize expands pwd.
+        if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+	    catch {set _gitworktree [exec git config --get core.worktree]}
+	    if {$_gitworktree eq ""} {
+		set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+	    }
+        }
+    }
+    return $_gitworktree
+}
+
 # A simple scheduler for compute-intensive stuff.
 # The aim is to make sure that event handlers for GUI actions can
 # run at least every 50-100 ms.  Unfortunately fileevent handlers are
@@ -7393,19 +7413,15 @@ proc startdiff {ids} {
     }
 }
 
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
 proc path_filter {filter name} {
+    set worktree [gitworktree]
     foreach p $filter {
-	set l [string length $p]
-	if {[string index $p end] eq "/"} {
-	    if {[string compare -length $l $p $name] == 0} {
-		return 1
-	    }
-	} else {
-	    if {[string compare -length $l $p $name] == 0 &&
-		([string length $name] == $l ||
-		 [string index $name $l] eq "/")} {
-		return 1
-	    }
+	set fq_p [file normalize $p]
+	set fq_n [file normalize [file join $worktree $name]]
+	if {[string match [file normalize $fq_p]* $fq_n]} {
+	    return 1
 	}
     }
     return 0

From 5c1bcba1e4ef083872d2de5b18a0866e0168e701 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 2730/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index f545ce34c5..b262ae389f 100644
--- a/Makefile
+++ b/Makefile
@@ -1288,6 +1288,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From 7b7f92ee052f674049505e1e2388b94116a3ce93 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 2731/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From c0e2b3c8f4c254025ad9cfb69f775604f5787c3d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 6 Jan 2012 13:56:09 -0600
Subject: [PATCH 2732/3720] Install Git/I18N.pm even in the absence of Perl's
 MakeMaker

The telltale was that t0202 could not find I18N.pm on msysGit.

Signed-off-by: Johannes Schindelin 
---
 perl/Makefile | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/perl/Makefile b/perl/Makefile
index b2977cd0bc..91848f3d3c 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -24,13 +24,15 @@ ifdef NO_PERL_MAKEMAKER
 instdir_SQ = $(subst ','\'',$(prefix)/lib)
 $(makfile): ../GIT-CFLAGS Makefile
 	echo all: private-Error.pm Git.pm > $@
-	echo '	mkdir -p blib/lib' >> $@
+	echo '	mkdir -p blib/lib/Git' >> $@
+	echo '	$(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@
 	echo '	$(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@
 	echo '	$(RM) blib/lib/Error.pm' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
 	echo '	cp private-Error.pm blib/lib/Error.pm' >> $@
 	echo install: >> $@
-	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)"' >> $@
+	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
+	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm "$$(DESTDIR)$(instdir_SQ)/Git/"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm "$$(DESTDIR)$(instdir_SQ)"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \

From bed84bf48f89b216723ebb625955e1e71a904da3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 2733/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index a782409306..79e575eac8 100644
--- a/Makefile
+++ b/Makefile
@@ -1181,16 +1181,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 3b3c4f46b3116573fbeab7c7d1db9b6700cc5ab3 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2734/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..57d5f59ca8 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 2a3f58c420ef5a3af4dec4fd63336d7389ae48c1 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2735/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 04f5e19dc3..468fdec8a1 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -152,6 +152,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 10afd71d43..bbc9a8cafa 100644
--- a/cache.h
+++ b/cache.h
@@ -604,6 +604,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..cc1b34999d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 57d5f59ca8..4acdac969d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -324,6 +321,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index 40f9c6d103..b6dcfa8f2e 100644
--- a/config.c
+++ b/config.c
@@ -686,6 +686,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index c93b8f44df..bf6f0c29ed 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 8f3972cd32..11d68b1104 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -577,4 +577,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 0c1cbec9abfe7f33eb0769bef46fb0e80b1f1bac Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2736/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index cc1b34999d..665f6abc40 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From d77f2fa4aec9a25457bca3b4e8a77cc196bb6fbc Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2737/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 9b14c5db062a22debab0ccdee79166490f94fd5c Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2738/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 9950ea4cec9cb6feff6bf994ad3975271db42e20 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2739/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 2208303cb930fe42a9988b4b8c89ee4e07dd5978 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2740/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 64ef3c4013..e2cda370fa 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9499,7 +9499,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 23357219e725fb5751b1d9bdcac3cacb2ff558a6 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2741/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 84fbcaf1b68ae7bd23c9d9e51cce1ef68d4e7340 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2742/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From cc12a2368e1ec03aeda113057237c005d2a6b0bc Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2743/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 468fdec8a1..c64b48743b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1705,6 +1705,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 8c9e91e78c..35c263bc27 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -88,7 +90,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -409,6 +416,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -440,6 +485,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -468,6 +520,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 2ccb811c5485d0220807dea8de684b33c175ab08 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2744/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d491db92c9..d1f09be986 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 4feae5efcca7609dd103cf59651c56f96b147609 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2745/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index d1f09be986..fd283e2625 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From e5dd45d0e94f811f428ebe33c661113cf3e42765 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2746/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index d35c06ae51..723703464f 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 665f6abc40..e5f1c36995 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 4acdac969d..4285272452 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -355,3 +355,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index b6dcfa8f2e..298bbcf2e5 100644
--- a/config.c
+++ b/config.c
@@ -897,7 +897,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 11d68b1104..4f9186559a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -581,4 +581,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 6470b7007669d9bba461838d8f6023ceb87680d3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2747/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From 09f3c5985c07557cbc92c1a2a3271a165159981b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2748/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 1c13b13991..8fbd2f8cff 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -556,7 +556,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -719,7 +720,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -795,7 +797,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -819,7 +821,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From e9493ed4cae9377b1f9c172cad34ebb531fcd2f3 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2749/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index a65dfc7ea9..de0a5d5fd8 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 90973c62637daef963ddeedb76da12a364384d2b Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2750/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index bbc9a8cafa..0a6962f06c 100644
--- a/cache.h
+++ b/cache.h
@@ -757,7 +757,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index e5f1c36995..39ce7b446d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 4285272452..74f7c6d247 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -315,6 +315,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 4f9186559a..1827cc797b 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 25eafb072275c906a81028dfd39c0b3bdb1f17f4 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2751/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index 723703464f..ffa3ff26ac 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From 33aa4de2cd55857ef66f8c6ee6cf5defd3628c5b Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2752/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 39ce7b446d..71adbc497a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 3be33ac021112afdca919191b6fc9fa90dcf3418 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2753/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 9ef6c7bf0362baed07602e24b9d0b1f10e65c52f Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2754/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index e2cda370fa..928a25d904 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -365,7 +365,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9499,18 +9499,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9521,6 +9510,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From c4b8603eff92214bfb5b4e8dd62ef099bcd6ec7e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2755/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 71adbc497a..fe3cae3a38 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From d4961237f479d9161b27a333268421192135dc2d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2756/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 74f7c6d247..9af6580651 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -296,9 +296,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 14f7f133b0834fbe1bc17499a6e6dbd7316b097a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2757/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 815bb62904e9d40fb1eea28dee4bf34c29e36e54 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2758/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 2747a24d474aa88963d3d50e410ea6cf7229faa4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2759/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index c719a6e385..0accb1f7a2 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From d2f59be845313c4822183fd61a924188ab4daf1a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2760/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 285fe88403..5596cfd637 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4302,6 +4302,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From f5038537bdb326004568ac0a9fa40ea512f8edc4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2761/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 5596cfd637..2996050e17 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4317,7 +4317,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 9e01adad7bb119994138493a1c41f29e5707d345 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2762/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 0ffd79cd81..3f3e3e72fd 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -138,6 +139,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From c2a9434fbb4b7a76111f2111bc779b3b7d496652 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2763/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index 1c42900ff8..b79336d712 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -280,6 +280,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From f8ae659d9f17d57661d24d779e089341493f7ebd Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2764/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 35c263bc27..de9cd9083d 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -419,7 +419,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 3a47ae13c230de7c735d722b7c250e6cf1302252 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2765/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 9ce064ac11..3589067dcc 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -205,6 +206,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -215,6 +232,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -530,6 +550,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -996,6 +1019,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 72b41f1327167e55c97afb179908cb83c27fb168 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2766/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 79e575eac8..7fa04aad10 100644
--- a/Makefile
+++ b/Makefile
@@ -301,7 +301,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From 8bebbfe0a02d3a20d4fa48811ee63e0825dc639f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2767/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index fe3cae3a38..f86800680c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 28832b70ec6fb92b7a007d149735e29b9bc38e83 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2768/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 7fa04aad10..3a4fb25885 100644
--- a/Makefile
+++ b/Makefile
@@ -2035,7 +2035,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2075,6 +2075,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From a2115f52070e69c4d223968f184c41bc5b9bb7b4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2769/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..18a93cba9f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 60a671c4473ebe5fdc5186349e259f89fddbf867 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2770/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 3589067dcc..35df5f540c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1088,6 +1088,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (!strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From fc87b9b0752f5167da03cc69f7774ef32a293fcc Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 17 Feb 2011 16:09:10 +0100
Subject: [PATCH 2771/3720] Amend "git grep -O -i: if the pager is 'less', pass
 the '-i' option"

This change was left in the stash, for some reason. Squash this in with
the next rebasing merge.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 35df5f540c..86af33e34a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1088,7 +1088,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
-		if (!strcmp("less", pager))
+		if (opt.ignore_case && !strcmp("less", pager))
 			string_list_append(&path_list, "-i");
 
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {

From 63c67953c8ba9c3446e69c632989296341e17c5f Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2772/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index 46f11a89de..938668f5a6 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -937,22 +937,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -967,11 +971,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 5160e5441e146e6fc0ee3d50442cd82a9faba3c7 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2773/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f86800680c..61a1230433 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 2f65cc20088c6f6a9e32b3392025d818dd456349 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2774/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 8e37e6ece5a7a5ad0de93b8d29b6b9f9dd64a143 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2775/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From f3143e4990d640d5fdc1db2eec1e968a9781afea Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2776/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2777/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93635..73f41482a8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -831,12 +831,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2778/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From d3d361a229f3a52cc5beaba2a9acd36e6907fb6a Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2779/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2780/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9af6580651..60e281a7fe 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 35587750356a30f1ee111b209e4e8b0246ec5f67 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2781/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3a4fb25885..956a7831e6 100644
--- a/Makefile
+++ b/Makefile
@@ -1175,6 +1175,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1268,6 +1269,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 05c3d2adb51a3892585cc14e6e344a25209bd765 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2782/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From fc390b37572357d10ab8a141fb6bf1d156b1350d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2783/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From af444c123e358ce730a3142d7ec93d85f1680bf9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2784/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 22ff352e9611eccaa75bed4ed7951c68f5d71f0c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2785/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 9bd7f249dea8dfc44c099e1ffa83b35766bd5e5f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2786/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 61a1230433..398c11f175 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 15aa00e42dae0c4c4cb40c39136972567b42a8d7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2787/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 398c11f175..8565118abd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 60e281a7fe..da9c53583a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From c1307b9e7527b078e84df75ce6e0501253af950a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2788/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8565118abd..1b40ff2373 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From ee8ad835a6d372b1ab9e314feeb29a94ade8d345 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2789/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 2996050e17..7415d03b12 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6607,7 +6607,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6655,6 +6667,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 6a1b7396acf26d269801874af3abbb96f32790ab Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2790/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 7415d03b12..05ecaf9851 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4302,7 +4302,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From b8e4bd88b813a1ec7019007829a8949a92554244 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2791/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 05ecaf9851..06a2f8a198 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6720,7 +6720,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 6155f6513513fff75c2d5f2791f0720bb5bbe50c Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2792/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1b40ff2373..952a2a6819 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 0c07b1eb8e9db6a23866a481db4904809842a2c0 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2793/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index da9c53583a..1f9f35f63d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 466810e42e7d457f94eb932a318b09a105b98595 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2794/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index d8b64d7a67..50f4855117 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -109,7 +110,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -274,7 +280,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From 89930a1c1aac2f4720f87fa5f537c9545bb4f176 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2795/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index c64b48743b..5a41ec9e6d 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -682,6 +682,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index 50f4855117..eec078300c 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 1cd34af1859f5d20ed3cc78768b50347f57d9dba Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 2796/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1f9f35f63d..407bad231b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 1827cc797b..e465862ea4 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From 577298b7f8036c27c7bb5470ea783f251e9e83b7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 2797/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From e3a81ac737da6888a7ad4ca3f57c2d1c36b6e956 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 2798/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 956a7831e6..052f285cda 100644
--- a/Makefile
+++ b/Makefile
@@ -1173,6 +1173,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From f4295c0924a2bb5063b966d30b373bc2b4cd2382 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 2799/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From d0e09527818bfecc0511796f313a39e4af808c04 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 2800/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 052f285cda..f545ce34c5 100644
--- a/Makefile
+++ b/Makefile
@@ -1251,7 +1251,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From 16014d290b328dded6c5c7309eeedd39035b06f6 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 16:50:50 +0000
Subject: [PATCH 2801/3720] gitk: fix the display of files when filtered by
 path

Launching 'gitk -- .' or 'gitk -- ..\t' restricts the display to files
under the given directory but the file list is left empty. This is because
the path_filter function fails to match the filenames which are relative
to the working tree to the filter which is filessytem relative.
This solves the problem by making both names fully qualified filesystem
paths before performing the comparison.

Signed-off-by: Pat Thoyts 
Tested-by: David Aguilar 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 928a25d904..77c38b01b6 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -14,6 +14,26 @@ proc hasworktree {} {
 		  [exec git rev-parse --is-inside-git-dir] == "false"}]
 }
 
+proc gitworktree {} {
+    variable _gitworktree
+    if {[info exists _gitworktree]} {
+	return $_gitworktree
+    }
+    # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+    if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+        # try to set work tree from environment, core.worktree or use
+        # cdup to obtain a relative path to the top of the worktree. If
+        # run from the top, the ./ prefix ensures normalize expands pwd.
+        if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+	    catch {set _gitworktree [exec git config --get core.worktree]}
+	    if {$_gitworktree eq ""} {
+		set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+	    }
+        }
+    }
+    return $_gitworktree
+}
+
 # A simple scheduler for compute-intensive stuff.
 # The aim is to make sure that event handlers for GUI actions can
 # run at least every 50-100 ms.  Unfortunately fileevent handlers are
@@ -7393,19 +7413,15 @@ proc startdiff {ids} {
     }
 }
 
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
 proc path_filter {filter name} {
+    set worktree [gitworktree]
     foreach p $filter {
-	set l [string length $p]
-	if {[string index $p end] eq "/"} {
-	    if {[string compare -length $l $p $name] == 0} {
-		return 1
-	    }
-	} else {
-	    if {[string compare -length $l $p $name] == 0 &&
-		([string length $name] == $l ||
-		 [string index $name $l] eq "/")} {
-		return 1
-	    }
+	set fq_p [file normalize $p]
+	set fq_n [file normalize [file join $worktree $name]]
+	if {[string match [file normalize $fq_p]* $fq_n]} {
+	    return 1
 	}
     }
     return 0

From 2d566d6500c91043b444b8c8feaf6a654c3f26ab Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 2802/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index f545ce34c5..b262ae389f 100644
--- a/Makefile
+++ b/Makefile
@@ -1288,6 +1288,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From a2413e8d1d20d5cb024cbc141187c7fbb3342ba8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 2803/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From b6e107841237a692219cc51b323b3f19b5fde86f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 6 Jan 2012 13:56:09 -0600
Subject: [PATCH 2804/3720] Install Git/I18N.pm even in the absence of Perl's
 MakeMaker

The telltale was that t0202 could not find I18N.pm on msysGit.

Signed-off-by: Johannes Schindelin 
---
 perl/Makefile | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/perl/Makefile b/perl/Makefile
index b2977cd0bc..91848f3d3c 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -24,13 +24,15 @@ ifdef NO_PERL_MAKEMAKER
 instdir_SQ = $(subst ','\'',$(prefix)/lib)
 $(makfile): ../GIT-CFLAGS Makefile
 	echo all: private-Error.pm Git.pm > $@
-	echo '	mkdir -p blib/lib' >> $@
+	echo '	mkdir -p blib/lib/Git' >> $@
+	echo '	$(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@
 	echo '	$(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@
 	echo '	$(RM) blib/lib/Error.pm' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
 	echo '	cp private-Error.pm blib/lib/Error.pm' >> $@
 	echo install: >> $@
-	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)"' >> $@
+	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
+	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm "$$(DESTDIR)$(instdir_SQ)/Git/"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm "$$(DESTDIR)$(instdir_SQ)"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \

From bfdd78f7576d2d5cc7fba6be98cce11a0a72051f Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Sun, 8 Jan 2012 15:04:45 -0800
Subject: [PATCH 2805/3720] Revert "daemon: add tests"

This reverts the cb/git-daemon-tests topic, to queue its fresh reroll.
---
 t/lib-git-daemon.sh   |  56 ----------------
 t/t5570-git-daemon.sh | 148 ------------------------------------------
 2 files changed, 204 deletions(-)
 delete mode 100644 t/lib-git-daemon.sh
 delete mode 100755 t/t5570-git-daemon.sh

diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh
deleted file mode 100644
index c0ff9e2b65..0000000000
--- a/t/lib-git-daemon.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-
-if test -z "$GIT_TEST_GIT_DAEMON"
-then
-	skip_all="git-daemon testing disabled (define GIT_TEST_GIT_DAEMON to enable)"
-	test_done
-fi
-
-LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-'8121'}
-
-GIT_DAEMON_PID=
-GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo
-GIT_DAEMON_URL=git://127.0.0.1:$LIB_GIT_DAEMON_PORT
-
-start_git_daemon() {
-	if test -n "$GIT_DAEMON_PID"
-	then
-		error "start_git_daemon already called"
-	fi
-
-	mkdir -p "$GIT_DAEMON_DOCUMENT_ROOT_PATH"
-
-	trap 'code=$?; stop_git_daemon; (exit $code); die' EXIT
-
-	say >&3 "Starting git daemon ..."
-	git daemon --listen=127.0.0.1 --port="$LIB_GIT_DAEMON_PORT" \
-		--reuseaddr --verbose \
-		--base-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH" \
-		"$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \
-		>&3 2>&4 &
-	GIT_DAEMON_PID=$!
-}
-
-stop_git_daemon() {
-	if test -z "$GIT_DAEMON_PID"
-	then
-		return
-	fi
-
-	trap 'die' EXIT
-
-	# kill git-daemon child of git
-	say >&3 "Stopping git daemon ..."
-	pkill -P "$GIT_DAEMON_PID"
-	wait "$GIT_DAEMON_PID"
-	ret=$?
-	#
-	# We signal TERM=15 to the child and expect the parent to
-	# exit with 143 = 128+15.
-	#
-	if test $ret -ne 143
-	then
-		error "git daemon exited with status: $ret"
-	fi
-	GIT_DAEMON_PID=
-}
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
deleted file mode 100755
index 7cbc9994a3..0000000000
--- a/t/t5570-git-daemon.sh
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/bin/sh
-
-test_description='test fetching over git protocol'
-. ./test-lib.sh
-
-LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570}
-. "$TEST_DIRECTORY"/lib-git-daemon.sh
-start_git_daemon
-
-test_expect_success 'setup repository' '
-	echo content >file &&
-	git add file &&
-	git commit -m one
-'
-
-test_expect_success 'create git-accessible bare repository' '
-	mkdir "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
-	(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
-	 git --bare init &&
-	 : >git-daemon-export-ok
-	) &&
-	git remote add public "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
-	git push public master:master
-'
-
-test_expect_success 'clone git repository' '
-	git clone "$GIT_DAEMON_URL/repo.git" clone &&
-	test_cmp file clone/file
-'
-
-test_expect_success 'fetch changes via git protocol' '
-	echo content >>file &&
-	git commit -a -m two &&
-	git push public &&
-	(cd clone && git pull) &&
-	test_cmp file clone/file
-'
-
-test_expect_failure 'remote detects correct HEAD' '
-	git push public master:other &&
-	(cd clone &&
-	 git remote set-head -d origin &&
-	 git remote set-head -a origin &&
-	 git symbolic-ref refs/remotes/origin/HEAD > output &&
-	 echo refs/remotes/origin/master > expect &&
-	 test_cmp expect output
-	)
-'
-
-test_expect_success 'prepare pack objects' '
-	cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git &&
-	(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git &&
-	 git --bare repack -a -d
-	)
-'
-
-test_expect_success 'fetch notices corrupt pack' '
-	cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
-	(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
-	 p=`ls objects/pack/pack-*.pack` &&
-	 chmod u+w $p &&
-	 printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
-	) &&
-	mkdir repo_bad1.git &&
-	(cd repo_bad1.git &&
-	 git --bare init &&
-	 test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad1.git" &&
-	 test 0 = `ls objects/pack/pack-*.pack | wc -l`
-	)
-'
-
-test_expect_success 'fetch notices corrupt idx' '
-	cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
-	(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
-	 p=`ls objects/pack/pack-*.idx` &&
-	 chmod u+w $p &&
-	 printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
-	) &&
-	mkdir repo_bad2.git &&
-	(cd repo_bad2.git &&
-	 git --bare init &&
-	 test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad2.git" &&
-	 test 0 = `ls objects/pack | wc -l`
-	)
-'
-
-test_remote_error()
-{
-	do_export=YesPlease
-	while test $# -gt 0
-	do
-		case $1 in
-		-x)
-			shift
-			chmod -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
-			;;
-		-n)
-			shift
-			do_export=
-			;;
-		*)
-			break
-		esac
-	done
-
-	if test $# -ne 3
-	then
-		error "invalid number of arguments"
-	fi
-
-	cmd=$1
-	repo=$2
-	msg=$3
-
-	if test -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo"
-	then
-		if test -n "$do_export"
-		then
-			: >"$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok"
-		else
-			rm -f "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok"
-		fi
-	fi
-
-	test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" 2>output &&
-	echo "fatal: remote error: $msg: /$repo" >expect &&
-	test_cmp expect output
-	ret=$?
-	chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
-	(exit $ret)
-}
-
-msg="access denied or repository not exported"
-test_expect_success 'clone non-existent' "test_remote_error    clone nowhere.git '$msg'"
-test_expect_success 'push disabled'      "test_remote_error    push  repo.git    '$msg'"
-test_expect_success 'read access denied' "test_remote_error -x fetch repo.git    '$msg'"
-test_expect_success 'not exported'       "test_remote_error -n fetch repo.git    '$msg'"
-
-stop_git_daemon
-start_git_daemon --informative-errors
-
-test_expect_success 'clone non-existent' "test_remote_error    clone nowhere.git 'no such repository'"
-test_expect_success 'push disabled'      "test_remote_error    push  repo.git    'service not enabled'"
-test_expect_success 'read access denied' "test_remote_error -x fetch repo.git    'no such repository'"
-test_expect_success 'not exported'       "test_remote_error -n fetch repo.git    'repository not exported'"
-
-stop_git_daemon
-test_done

From 30a615ac66d2e650e5fc3dc2dfdae705410800ab Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 9 Jan 2012 19:16:30 +0100
Subject: [PATCH 2806/3720] Windows/i18n: rename $path to prevent clashes with
 $PATH

Environment variables on Windows are case-insensitive. Rename '$path' in
all calls to eval_gettext to $modulepath so that it is not mistakenly
expanded to the value of the $PATH variable.

[jes: this happens to fix t7406/t7407 on Windows]

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 git-submodule.sh | 52 ++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index de06bc1471..0a37d70f04 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -105,7 +105,7 @@ module_name()
 	name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
 	test -z "$name" &&
-	die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+	die "$(modulepath=$path eval_gettext "No submodule mapping found in .gitmodules for path '\$modulepath'")"
 	echo "$name"
 }
 
@@ -169,7 +169,7 @@ module_clone()
 		else
 			git-clone $quiet -n "$url" "$path" --separate-git-dir "$gitdir"
 		fi ||
-		die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+		die "$(modulepath=$path eval_gettext "Clone of '\$url' into submodule path '\$modulepath' failed")"
 	fi
 }
 
@@ -260,13 +260,13 @@ cmd_add()
 			s|/*$||
 		')
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
-	die "$(eval_gettext "'\$path' already exists in the index")"
+	die "$(modulepath=$path eval_gettext "'\$modulepath' already exists in the index")"
 
 	if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
 	then
 		cat >&2 </dev/null) &&
 					 test -z "$rev") || git-fetch)) ||
-				die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
+				die "$(modulepath=$path eval_gettext "Unable to fetch in submodule path '\$modulepath'")"
 			fi
 
 			# Is this something we just cloned?
@@ -563,20 +563,20 @@ Maybe you want to use 'update --init'?")"
 			case "$update_module" in
 			rebase)
 				command="git rebase"
-				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to rebase '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': rebased into '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			merge)
 				command="git merge"
-				die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to merge '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': merged in '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			*)
 				command="git checkout $subforce -q"
-				die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to checkout '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': checked out '\$sha1'")"
 				;;
 			esac
 
@@ -598,7 +598,7 @@ Maybe you want to use 'update --init'?")"
 			res=$?
 			if test $res -gt 0
 			then
-				die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+				die_msg="$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 				if test $res -eq 1
 				then
 					err="${err};$die_msg"
@@ -925,7 +925,7 @@ cmd_status()
 				cd "$path" &&
 				eval cmd_status "$orig_args"
 			) ||
-			die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+			die "$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 		fi
 	done
 }

From e032974a6b43e1c11055236f300aecadc7249983 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Wed, 11 Jan 2012 16:31:27 +0000
Subject: [PATCH 2807/3720] amend 30a615a: Fix a substitution order error that
 breaks t7400

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
---
 git-submodule.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 0a37d70f04..aa6b5f2a13 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -266,7 +266,7 @@ cmd_add()
 	then
 		cat >&2 <
Date: Wed, 11 Jan 2012 10:20:14 +0100
Subject: [PATCH 2808/3720] t9200: On MSYS, do not pass Windows-style paths to
 CVS

For details, see the commit message of 4114156ae9. Note that while using
$PWD as part of GIT_DIR is not required here, it does no harm and it is
more consistent. In addition, on MSYS using an environment variable should
be slightly faster than spawning an external executable.

Signed-off-by: Sebastian Schuberth 
---
 t/t9200-git-cvsexportcommit.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index 41db05cb4a..518358aa64 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -19,9 +19,9 @@ then
     test_done
 fi
 
-CVSROOT=$(pwd)/cvsroot
-CVSWORK=$(pwd)/cvswork
-GIT_DIR=$(pwd)/.git
+CVSROOT=$PWD/cvsroot
+CVSWORK=$PWD/cvswork
+GIT_DIR=$PWD/.git
 export CVSROOT CVSWORK GIT_DIR
 
 rm -rf "$CVSROOT" "$CVSWORK"

From 578cb11c4aef24fd331362390e53c5a8e242d662 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 11 Jan 2012 10:21:10 +0100
Subject: [PATCH 2809/3720] git-cvsexportcommit: Fix calling Perl's rel2abs()
 on MSYS

Due to MSYS path mangling GIT_DIR contains a Windows-style path when
checked inside a Perl script even if GIT_DIR was previously set to an
MSYS-style path in a shell script. So explicitly convert to an MSYS-style
path before calling Perl's rel2abs() to make it work.

This fix was inspired by a very similar patch in WebKit:

http://trac.webkit.org/changeset/76255/trunk/Tools/Scripts/commit-log-editor

Tested-by: Pat Thoyts 
Signed-off-by: Sebastian Schuberth 
---
 git-cvsexportcommit.perl | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index 39a426e067..e6bf25232c 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -30,6 +30,13 @@ if ($opt_w || $opt_W) {
 		chomp($gd);
 		$ENV{GIT_DIR} = $gd;
 	}
+
+	# On MSYS, convert a Windows-style path to an MSYS-style path
+	# so that rel2abs() below works correctly.
+	if ($^O eq 'msys') {
+		$ENV{GIT_DIR} =~ s#^([[:alpha:]]):/#/$1/#;
+	}
+
 	# Make sure GIT_DIR is absolute
 	$ENV{GIT_DIR} = File::Spec->rel2abs($ENV{GIT_DIR});
 }

From ecc6601e4c47dd783cacf711faed4601de01a850 Mon Sep 17 00:00:00 2001
From: Matthieu Moy 
Date: Sat, 14 Jan 2012 19:55:36 +0100
Subject: [PATCH 2810/3720] bash-completion: don't add quoted space for ZSH
 (fix regression)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit a31e626 (completion: optimize refs completion) introduced a
regression for ZSH users: ref names were completed with a quoted trailing
space (i.e. "git checkout ma" completes to "git checkout master\ "). The
space is convenient for bash users since we use "-o nospace", but a
quoted space is worse than nothing. The absence of trailing space for ZSH
is a long-standing issue, that this patch is not fixing. We just fix the
regression by not appending a space when the shell is ZSH.

Original-patch-by: SZEDER Gábor 
Reported-by: Stefan Haller 
Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 contrib/completion/git-completion.bash | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index b0062bac22..488e1f4445 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -534,6 +534,12 @@ __gitcomp_nl ()
 		fi
 	fi
 
+	# ZSH would quote the trailing space added with -S. bash users
+	# will appreciate the extra space to compensate the use of -o nospace.
+	if [ -n "${ZSH_VERSION-}" ] && [ "$suffix" = " " ]; then
+		suffix=""
+	fi
+
 	IFS=$s
 	COMPREPLY=($(compgen -P "${2-}" -S "$suffix" -W "$1" -- "$cur_"))
 }

From 300bda9bd68f916f697eff32280d71259b081270 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 2811/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index c457c34fe9..33d5457dd1 100644
--- a/Makefile
+++ b/Makefile
@@ -1184,16 +1184,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 8e46bf78f678b50cbb7cf8ec341c11e3b254fe62 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Mon, 28 Dec 2009 18:13:52 +0100
Subject: [PATCH 2812/3720] MinGW: Add missing file mode bit defines

Signed-off-by: Sebastian Schuberth 
---
 compat/mingw.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..57d5f59ca8 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,6 +14,12 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
+#ifndef _STAT_H_
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define S_IXUSR 0
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From b1bee33412b6845d10df6ca42efe005b91ac8f98 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2813/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index abeb82b2c6..32c52aff8a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -152,6 +152,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 9bd8c2d06c..7e6e68cf71 100644
--- a/cache.h
+++ b/cache.h
@@ -604,6 +604,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..cc1b34999d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 57d5f59ca8..4acdac969d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -119,10 +119,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -324,6 +321,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index 40f9c6d103..b6dcfa8f2e 100644
--- a/config.c
+++ b/config.c
@@ -686,6 +686,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index c93b8f44df..bf6f0c29ed 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 8f3972cd32..11d68b1104 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -577,4 +577,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From fff307721a973d449b9e0ed01251bdc422331c48 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2814/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index cc1b34999d..665f6abc40 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 3925305982ce658c74acf7d0518435c2e405c504 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2815/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 92402f0f7ce74b951d9bb7b8466cd57ae899d540 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2816/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 5bc9d81955ae80ba5169bcb9a91f4dca9c2dc313 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2817/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 12efad03b63905e1ce7dc011128c36ef8ee8ab7b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2818/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 64ef3c4013..e2cda370fa 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9499,7 +9499,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From d6148c5ab088c88085da6b163d2ec36e0f528f1d Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2819/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 9c74a2553a2879f0cad3c205b2eede1dd942e94b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2820/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 8cbc45c882a4e6f4a6f01fd5798448883b8d924c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2821/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 32c52aff8a..6c74906c84 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1705,6 +1705,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index fa7448be5a..b3d631f95d 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -89,7 +91,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -410,6 +417,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -441,6 +486,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -469,6 +521,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 6da809f479d2325562bc335051a66ca3200a8cb7 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2822/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index ef30c557c7..c42fb2a7aa 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From f3ee35fb1cc9ea27a5e014887f821b5d9fd336fa Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2823/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index c42fb2a7aa..03292fd832 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 5f0eeb459b6e027796dcecf4bd3a6e50ab7c6eb2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2824/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index d35c06ae51..723703464f 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -164,7 +164,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 665f6abc40..e5f1c36995 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 4acdac969d..4285272452 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -355,3 +355,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index b6dcfa8f2e..298bbcf2e5 100644
--- a/config.c
+++ b/config.c
@@ -897,7 +897,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 11d68b1104..4f9186559a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -581,4 +581,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index b6f71d1086..9e5bf53ea8 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 4e319b9fd2e51a688216528bf205293572eb308c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2825/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36baa1f..732a11228c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From ee50be018baa9c833c1fb3f2621fbc63116efd78 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2826/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 64d8e2a64d..bb16a7bcb1 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -559,7 +559,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -731,7 +732,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -807,7 +809,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -831,7 +833,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From eb953bde9080b8436c7819a8a82bcba8e0daf4f4 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2827/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index b22bee7c84..521b74872f 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 43242470f6bf9b7611d6a81cdca61bc41e79131f Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2828/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 7e6e68cf71..1027935225 100644
--- a/cache.h
+++ b/cache.h
@@ -757,7 +757,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index e5f1c36995..39ce7b446d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 4285272452..74f7c6d247 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -315,6 +315,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 4f9186559a..1827cc797b 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 9e5bf53ea8..7d62e10f25 100644
--- a/path.c
+++ b/path.c
@@ -657,10 +657,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 845f325146824b4de44106d4caf07584238a45cf Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2829/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index 723703464f..ffa3ff26ac 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -363,7 +363,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From 9a378c586e90991ab88e306ac004cf4749125116 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2830/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 39ce7b446d..71adbc497a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 1aa29d2ed2976000b8c4de7069d71d000de14124 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2831/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 2604411e2cfd33f560563a2576f74e064276b6ed Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2832/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index e2cda370fa..928a25d904 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -365,7 +365,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9499,18 +9499,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9521,6 +9510,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 85e3d57704287e6edbaae16c5d262be8608ec1c8 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2833/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 71adbc497a..fe3cae3a38 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 277d7843d38b3429e49a283e0ed671391137b269 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2834/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 74f7c6d247..9af6580651 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -296,9 +296,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 26a90188efba7946ebabb77fd969d28032b61999 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2835/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 7a3edda1accf08bb1a4972a8aeda9c696fc68fbc Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2836/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 93080680933f373ad15d8336044a59abf4b3abe7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2837/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index cea8756866..9be97ab9ae 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From bf6410c33dbdb8a9ac06e7d6b4dafc740f66a412 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2838/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 9cf7e714a9..6abcbf0dbc 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4304,6 +4304,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From b77f3672b5a36aee08020a7ceb431562a865eb22 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2839/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 6abcbf0dbc..fc3cb2c222 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4319,7 +4319,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 0d43b1eb0b0738c238a8bb9c747f908202c45977 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2840/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 0ffd79cd81..3f3e3e72fd 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -138,6 +139,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 49651345e20fc5f6a84320943f1dc7117eb51867 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 07:56:21 -0700
Subject: [PATCH 2841/3720] add -e: ignore dirty submodules

We cannot add untracked/modified files in submodules anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/add.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/add.c b/builtin/add.c
index 1c42900ff8..b79336d712 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -280,6 +280,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 	out = open(file, O_CREAT | O_WRONLY, 0644);
 	if (out < 0)
 		die (_("Could not open '%s' for writing."), file);

From 689cf36f87739636ed83797ec92d0183469053fe Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2842/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index b3d631f95d..64a499f6e5 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -420,7 +420,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 572f36c969ac440c36fe8205c2f18bb8dd6a3b37 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2843/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 5c2ae94e55..f80b196d75 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -205,6 +206,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -215,6 +232,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		if (w->type == WORK_SHA1) {
 			unsigned long sz;
@@ -530,6 +550,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -996,6 +1019,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 4c2b1a0955c8778293663e528c95ac7678f051b1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2844/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 33d5457dd1..8f5cb2d270 100644
--- a/Makefile
+++ b/Makefile
@@ -304,7 +304,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From ff443111226b9a84c21647aef9fe5252d20d9486 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2845/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index fe3cae3a38..f86800680c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From e0fbd4cf5bbb02764cd6e79d5543ed36289ec749 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2846/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 8f5cb2d270..a2d0ca7d66 100644
--- a/Makefile
+++ b/Makefile
@@ -2040,7 +2040,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2080,6 +2080,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 85438e6a750c2fb3c544a34ad2158166c868f221 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2847/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..18a93cba9f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 8c6894c544bd2942d8ffc8be58921a10131ddd63 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2848/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index f80b196d75..241bc25294 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1089,6 +1089,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From af55874968c3d1df8fc11f984fe65fa3f997d154 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2849/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index 46f11a89de..938668f5a6 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -937,22 +937,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -967,11 +971,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 5b4d170e17f7c5937ae091a3c77edd26972f58e1 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2850/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f86800680c..61a1230433 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 402d2bdb44e3a146f9f32b544a915ced0f9093b6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2851/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From a95adf409527233cbfad5d2b7984d2b4ac5a9b85 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 16:44:45 +0200
Subject: [PATCH 2852/3720] Disable test on MinGW that challenges its bash
 quoting

Signed-off-by: Johannes Schindelin 
---
 t/t5505-remote.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e8af615e6d..1ad3551a6f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,7 +946,10 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	test_must_fail git remote set-url --delete someremote .\* &&
+	if test_have_prereq NOT_MINGW
+	then
+		test_must_fail git remote set-url --delete someremote .\*
+	fi &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From edb73f9df6ddfada9b6653d6a451916ba6090e4e Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2853/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2854/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 9bb2e13e92..c388bf11bf 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -832,12 +832,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2855/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From c568301383e325ff5b7b7f5cea8e619623df280c Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2856/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1fba6c2de0..1ca3d91c4c 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Wed, 15 Jun 2011 16:57:59 +0200
Subject: [PATCH 2857/3720] Revert "MinGW: Add missing file mode bit defines"

This reverts commit 5ff1232f6360c596bcaba9aa74991e28ea9b800a.
---
 compat/mingw.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9af6580651..60e281a7fe 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0

From 3357147342a0101d5a79c70982ed49b794777c05 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2858/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index a2d0ca7d66..099c5ab894 100644
--- a/Makefile
+++ b/Makefile
@@ -1178,6 +1178,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1271,6 +1272,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 1a7ef385d4c9366836427b57eeec13954f55adf0 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2859/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 7d14fe856e79bc9d24fb2619c1cd91c2069b5f8a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2860/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From 4e5b518ccc2d820f4697ef0724ae125a35e6d231 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2861/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From ff2471eceb278a76eb82040e7abf23052f931dfc Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2862/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 58274b469ef44cf84362e3378b5a0a69fd364100 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2863/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 61a1230433..398c11f175 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 3b7f31fd5a8032f6e7da2dc222c88b5f27036de1 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2864/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 398c11f175..8565118abd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 60e281a7fe..da9c53583a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From b666eb361250251f5f3cefb858799b3a568a5094 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2865/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8565118abd..1b40ff2373 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From e364e4a67dfaca28194e01b75434cddc3ccf6f54 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2866/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index fc3cb2c222..d51f5f11a9 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6609,7 +6609,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6657,6 +6669,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From a74d49a658aab24646cbb73f531918c12c7c0cd9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2867/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index d51f5f11a9..90879b3815 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4304,7 +4304,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From e365d7249d0883cb92c67647c4effee182c45a49 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2868/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 90879b3815..d9d8b6fbbc 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6722,7 +6722,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From a183e2eee4ffc62a352e50815c4bb30c2a7d6822 Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2869/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1b40ff2373..952a2a6819 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 2c503b231ff4606e1016271049e247dfd4af8f98 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2870/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index da9c53583a..1f9f35f63d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 74e61c245892d1ed54ee42f5bee241bd85efb09b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2871/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index d8b64d7a67..50f4855117 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -109,7 +110,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -274,7 +280,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From dd0f3a3c0f6df4779bddd95c8dd9045898d8f62b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2872/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 6c74906c84..cd3329a2a9 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -682,6 +682,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index 50f4855117..eec078300c 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 09d3918d0354771d53c0a874751345d750678fda Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 2873/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1f9f35f63d..407bad231b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 1827cc797b..e465862ea4 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From f634e7ebac505ce507f16ad7e00f34cd2d392aec Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 2874/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From c5ae654abf15675d00633c1bd154bc0ef3354335 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 2875/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 099c5ab894..3792d193bc 100644
--- a/Makefile
+++ b/Makefile
@@ -1176,6 +1176,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From 71f4bd21981d081413439ac2f5860772bb8c0707 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 2876/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From 5e20e60bd73f3292a3142cc0e1f805533e75b8a0 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 2877/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3792d193bc..ba6f3079eb 100644
--- a/Makefile
+++ b/Makefile
@@ -1254,7 +1254,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From 6ba5245babe194211afbbbc70bbe1694db17a36c Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 16:50:50 +0000
Subject: [PATCH 2878/3720] gitk: fix the display of files when filtered by
 path

Launching 'gitk -- .' or 'gitk -- ..\t' restricts the display to files
under the given directory but the file list is left empty. This is because
the path_filter function fails to match the filenames which are relative
to the working tree to the filter which is filessytem relative.
This solves the problem by making both names fully qualified filesystem
paths before performing the comparison.

Signed-off-by: Pat Thoyts 
Tested-by: David Aguilar 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 928a25d904..77c38b01b6 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -14,6 +14,26 @@ proc hasworktree {} {
 		  [exec git rev-parse --is-inside-git-dir] == "false"}]
 }
 
+proc gitworktree {} {
+    variable _gitworktree
+    if {[info exists _gitworktree]} {
+	return $_gitworktree
+    }
+    # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+    if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+        # try to set work tree from environment, core.worktree or use
+        # cdup to obtain a relative path to the top of the worktree. If
+        # run from the top, the ./ prefix ensures normalize expands pwd.
+        if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+	    catch {set _gitworktree [exec git config --get core.worktree]}
+	    if {$_gitworktree eq ""} {
+		set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+	    }
+        }
+    }
+    return $_gitworktree
+}
+
 # A simple scheduler for compute-intensive stuff.
 # The aim is to make sure that event handlers for GUI actions can
 # run at least every 50-100 ms.  Unfortunately fileevent handlers are
@@ -7393,19 +7413,15 @@ proc startdiff {ids} {
     }
 }
 
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
 proc path_filter {filter name} {
+    set worktree [gitworktree]
     foreach p $filter {
-	set l [string length $p]
-	if {[string index $p end] eq "/"} {
-	    if {[string compare -length $l $p $name] == 0} {
-		return 1
-	    }
-	} else {
-	    if {[string compare -length $l $p $name] == 0 &&
-		([string length $name] == $l ||
-		 [string index $name $l] eq "/")} {
-		return 1
-	    }
+	set fq_p [file normalize $p]
+	set fq_n [file normalize [file join $worktree $name]]
+	if {[string match [file normalize $fq_p]* $fq_n]} {
+	    return 1
 	}
     }
     return 0

From 745849f61b45b17957e6546f4aa85ceced89aec7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 2879/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index ba6f3079eb..4c65206ea7 100644
--- a/Makefile
+++ b/Makefile
@@ -1291,6 +1291,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From 480161d79511dab8e220361c8ae1864b598046c3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 2880/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From 8a86e2772b78d046ee934cc545daf13390d8cbbe Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 6 Jan 2012 13:56:09 -0600
Subject: [PATCH 2881/3720] Install Git/I18N.pm even in the absence of Perl's
 MakeMaker

The telltale was that t0202 could not find I18N.pm on msysGit.

Signed-off-by: Johannes Schindelin 
---
 perl/Makefile | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/perl/Makefile b/perl/Makefile
index b2977cd0bc..91848f3d3c 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -24,13 +24,15 @@ ifdef NO_PERL_MAKEMAKER
 instdir_SQ = $(subst ','\'',$(prefix)/lib)
 $(makfile): ../GIT-CFLAGS Makefile
 	echo all: private-Error.pm Git.pm > $@
-	echo '	mkdir -p blib/lib' >> $@
+	echo '	mkdir -p blib/lib/Git' >> $@
+	echo '	$(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@
 	echo '	$(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@
 	echo '	$(RM) blib/lib/Error.pm' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
 	echo '	cp private-Error.pm blib/lib/Error.pm' >> $@
 	echo install: >> $@
-	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)"' >> $@
+	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
+	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm "$$(DESTDIR)$(instdir_SQ)/Git/"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm "$$(DESTDIR)$(instdir_SQ)"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \

From e90b9c2eb9580f45d77d3849e5f14406bb76efcd Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 9 Jan 2012 19:16:30 +0100
Subject: [PATCH 2882/3720] Windows/i18n: rename $path to prevent clashes with
 $PATH

Environment variables on Windows are case-insensitive. Rename '$path' in
all calls to eval_gettext to $modulepath so that it is not mistakenly
expanded to the value of the $PATH variable.

[jes: this happens to fix t7406/t7407 on Windows]
[pt: squashed in fix for substitution order error that broke t7400]

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
---
 git-submodule.sh | 52 ++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 05286ff400..8f67e7f5fe 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -105,7 +105,7 @@ module_name()
 	name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
 	test -z "$name" &&
-	die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+	die "$(modulepath=$path eval_gettext "No submodule mapping found in .gitmodules for path '\$modulepath'")"
 	echo "$name"
 }
 
@@ -170,7 +170,7 @@ module_clone()
 		else
 			git-clone $quiet -n "$url" "$path" --separate-git-dir "$gitdir"
 		fi ||
-		die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+		die "$(modulepath=$path eval_gettext "Clone of '\$url' into submodule path '\$modulepath' failed")"
 	fi
 }
 
@@ -261,13 +261,13 @@ cmd_add()
 			s|/*$||
 		')
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
-	die "$(eval_gettext "'\$path' already exists in the index")"
+	die "$(modulepath=$path eval_gettext "'\$modulepath' already exists in the index")"
 
 	if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
 	then
 		cat >&2 </dev/null) &&
 					 test -z "$rev") || git-fetch)) ||
-				die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
+				die "$(modulepath=$path eval_gettext "Unable to fetch in submodule path '\$modulepath'")"
 			fi
 
 			# Is this something we just cloned?
@@ -564,20 +564,20 @@ Maybe you want to use 'update --init'?")"
 			case "$update_module" in
 			rebase)
 				command="git rebase"
-				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to rebase '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': rebased into '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			merge)
 				command="git merge"
-				die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to merge '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': merged in '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			*)
 				command="git checkout $subforce -q"
-				die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to checkout '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': checked out '\$sha1'")"
 				;;
 			esac
 
@@ -599,7 +599,7 @@ Maybe you want to use 'update --init'?")"
 			res=$?
 			if test $res -gt 0
 			then
-				die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+				die_msg="$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 				if test $res -eq 1
 				then
 					err="${err};$die_msg"
@@ -926,7 +926,7 @@ cmd_status()
 				cd "$path" &&
 				eval cmd_status "$orig_args"
 			) ||
-			die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+			die "$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 		fi
 	done
 }

From 8f5deba2d847f1262de71629a39dff62e564ee3d Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 14:56:49 +0000
Subject: [PATCH 2883/3720] gitk: use a tabbed dialog to edit preferences

This commit converts the user preferences dialog into a tabbed property
sheet grouping general properties, colours and font selections onto
separate pages. The previous implementation was exceeding the screen
height on some systems and this avoids such problems and permits extension
using new pages in the future.

If themed Tk is unavailable or undesired a reasonable facsimile of the
tabbed notebook widget is used instead.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 256 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 160 insertions(+), 96 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 77c38b01b6..dcae0a7547 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10805,6 +10805,139 @@ proc chg_fontparam {v sub op} {
     font config sample -$sub $fontparam($sub)
 }
 
+# Create a property sheet tab page
+proc create_prefs_page {w} {
+    global NS
+    set parent [join [lrange [split $w .] 0 end-1] .]
+    if {[winfo class $parent] eq "TNotebook"} {
+	${NS}::frame $w
+    } else {
+	${NS}::labelframe $w
+    }
+}
+
+proc prefspage_general {notebook} {
+    global NS maxwidth maxgraphpct showneartags showlocalchanges
+    global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
+    global hideremotes want_ttk have_ttk
+
+    set page [create_prefs_page $notebook.general]
+
+    ${NS}::label $page.ldisp -text [mc "Commit list display options"]
+    grid $page.ldisp - -sticky w -pady 10
+    ${NS}::label $page.spacer -text " "
+    ${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"]
+    spinbox $page.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+    grid $page.spacer $page.maxwidthl $page.maxwidth -sticky w
+    ${NS}::label $page.maxpctl -text [mc "Maximum graph width (% of pane)"]
+    spinbox $page.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+    grid x $page.maxpctl $page.maxpct -sticky w
+    ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \
+	-variable showlocalchanges
+    grid x $page.showlocal -sticky w
+    ${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \
+	-variable autoselect
+    spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
+    grid x $page.autoselect $page.autosellen -sticky w
+    ${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \
+	-variable hideremotes
+    grid x $page.hideremotes -sticky w
+
+    ${NS}::label $page.ddisp -text [mc "Diff display options"]
+    grid $page.ddisp - -sticky w -pady 10
+    ${NS}::label $page.tabstopl -text [mc "Tab spacing"]
+    spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
+    grid x $page.tabstopl $page.tabstop -sticky w
+    ${NS}::checkbutton $page.ntag -text [mc "Display nearby tags"] \
+	-variable showneartags
+    grid x $page.ntag -sticky w
+    ${NS}::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \
+	-variable limitdiffs
+    grid x $page.ldiff -sticky w
+    ${NS}::checkbutton $page.lattr -text [mc "Support per-file encodings"] \
+	-variable perfile_attrs
+    grid x $page.lattr -sticky w
+
+    ${NS}::entry $page.extdifft -textvariable extdifftool
+    ${NS}::frame $page.extdifff
+    ${NS}::label $page.extdifff.l -text [mc "External diff tool" ]
+    ${NS}::button $page.extdifff.b -text [mc "Choose..."] -command choose_extdiff
+    pack $page.extdifff.l $page.extdifff.b -side left
+    pack configure $page.extdifff.l -padx 10
+    grid x $page.extdifff $page.extdifft -sticky ew
+
+    ${NS}::label $page.lgen -text [mc "General options"]
+    grid $page.lgen - -sticky w -pady 10
+    ${NS}::checkbutton $page.want_ttk -variable want_ttk \
+	-text [mc "Use themed widgets"]
+    if {$have_ttk} {
+	${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
+    } else {
+	${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
+    }
+    grid x $page.want_ttk $page.ttk_note -sticky w
+    return $page
+}
+
+proc prefspage_colors {notebook} {
+    global NS uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+
+    set page [create_prefs_page $notebook.colors]
+
+    ${NS}::label $page.cdisp -text [mc "Colors: press to choose"]
+    grid $page.cdisp - -sticky w -pady 10
+    label $page.ui -padx 40 -relief sunk -background $uicolor
+    ${NS}::button $page.uibut -text [mc "Interface"] \
+       -command [list choosecolor uicolor {} $page.ui [mc "interface"] setui]
+    grid x $page.uibut $page.ui -sticky w
+    label $page.bg -padx 40 -relief sunk -background $bgcolor
+    ${NS}::button $page.bgbut -text [mc "Background"] \
+	-command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
+    grid x $page.bgbut $page.bg -sticky w
+    label $page.fg -padx 40 -relief sunk -background $fgcolor
+    ${NS}::button $page.fgbut -text [mc "Foreground"] \
+	-command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
+    grid x $page.fgbut $page.fg -sticky w
+    label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
+    ${NS}::button $page.diffoldbut -text [mc "Diff: old lines"] \
+	-command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
+		      [list $ctext tag conf d0 -foreground]]
+    grid x $page.diffoldbut $page.diffold -sticky w
+    label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
+    ${NS}::button $page.diffnewbut -text [mc "Diff: new lines"] \
+	-command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
+		      [list $ctext tag conf dresult -foreground]]
+    grid x $page.diffnewbut $page.diffnew -sticky w
+    label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
+    ${NS}::button $page.hunksepbut -text [mc "Diff: hunk header"] \
+	-command [list choosecolor diffcolors 2 $page.hunksep \
+		      [mc "diff hunk header"] \
+		      [list $ctext tag conf hunksep -foreground]]
+    grid x $page.hunksepbut $page.hunksep -sticky w
+    label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor
+    ${NS}::button $page.markbgbut -text [mc "Marked line bg"] \
+	-command [list choosecolor markbgcolor {} $page.markbgsep \
+		      [mc "marked line background"] \
+		      [list $ctext tag conf omark -background]]
+    grid x $page.markbgbut $page.markbgsep -sticky w
+    label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor
+    ${NS}::button $page.selbgbut -text [mc "Select bg"] \
+	-command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
+    grid x $page.selbgbut $page.selbgsep -sticky w
+    return $page
+}
+
+proc prefspage_fonts {notebook} {
+    global NS
+    set page [create_prefs_page $notebook.fonts]
+    ${NS}::label $page.cfont -text [mc "Fonts: press to choose"]
+    grid $page.cfont - -sticky w -pady 10
+    mkfontdisp mainfont $page [mc "Main font"]
+    mkfontdisp textfont $page [mc "Diff display font"]
+    mkfontdisp uifont $page [mc "User interface font"]
+    return $page
+}
+
 proc doprefs {} {
     global maxwidth maxgraphpct use_ttk NS
     global oldprefs prefstop showneartags showlocalchanges
@@ -10825,106 +10958,37 @@ proc doprefs {} {
     ttk_toplevel $top
     wm title $top [mc "Gitk preferences"]
     make_transient $top .
-    ${NS}::label $top.ldisp -text [mc "Commit list display options"]
-    grid $top.ldisp - -sticky w -pady 10
-    ${NS}::label $top.spacer -text " "
-    ${NS}::label $top.maxwidthl -text [mc "Maximum graph width (lines)"]
-    spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
-    grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
-    ${NS}::label $top.maxpctl -text [mc "Maximum graph width (% of pane)"]
-    spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
-    grid x $top.maxpctl $top.maxpct -sticky w
-    ${NS}::checkbutton $top.showlocal -text [mc "Show local changes"] \
-	-variable showlocalchanges
-    grid x $top.showlocal -sticky w
-    ${NS}::checkbutton $top.autoselect -text [mc "Auto-select SHA1 (length)"] \
-	-variable autoselect
-    spinbox $top.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
-    grid x $top.autoselect $top.autosellen -sticky w
-    ${NS}::checkbutton $top.hideremotes -text [mc "Hide remote refs"] \
-	-variable hideremotes
-    grid x $top.hideremotes -sticky w
 
-    ${NS}::label $top.ddisp -text [mc "Diff display options"]
-    grid $top.ddisp - -sticky w -pady 10
-    ${NS}::label $top.tabstopl -text [mc "Tab spacing"]
-    spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
-    grid x $top.tabstopl $top.tabstop -sticky w
-    ${NS}::checkbutton $top.ntag -text [mc "Display nearby tags"] \
-	-variable showneartags
-    grid x $top.ntag -sticky w
-    ${NS}::checkbutton $top.ldiff -text [mc "Limit diffs to listed paths"] \
-	-variable limitdiffs
-    grid x $top.ldiff -sticky w
-    ${NS}::checkbutton $top.lattr -text [mc "Support per-file encodings"] \
-	-variable perfile_attrs
-    grid x $top.lattr -sticky w
-
-    ${NS}::entry $top.extdifft -textvariable extdifftool
-    ${NS}::frame $top.extdifff
-    ${NS}::label $top.extdifff.l -text [mc "External diff tool" ]
-    ${NS}::button $top.extdifff.b -text [mc "Choose..."] -command choose_extdiff
-    pack $top.extdifff.l $top.extdifff.b -side left
-    pack configure $top.extdifff.l -padx 10
-    grid x $top.extdifff $top.extdifft -sticky ew
-
-    ${NS}::label $top.lgen -text [mc "General options"]
-    grid $top.lgen - -sticky w -pady 10
-    ${NS}::checkbutton $top.want_ttk -variable want_ttk \
-	-text [mc "Use themed widgets"]
-    if {$have_ttk} {
-	${NS}::label $top.ttk_note -text [mc "(change requires restart)"]
+    if {[set use_notebook [expr {$use_ttk && [info command ::ttk::notebook] ne ""}]]} {
+	set notebook [ttk::notebook $top.notebook]
     } else {
-	${NS}::label $top.ttk_note -text [mc "(currently unavailable)"]
+	set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat]
     }
-    grid x $top.want_ttk $top.ttk_note -sticky w
 
-    ${NS}::label $top.cdisp -text [mc "Colors: press to choose"]
-    grid $top.cdisp - -sticky w -pady 10
-    label $top.ui -padx 40 -relief sunk -background $uicolor
-    ${NS}::button $top.uibut -text [mc "Interface"] \
-       -command [list choosecolor uicolor {} $top.ui [mc "interface"] setui]
-    grid x $top.uibut $top.ui -sticky w
-    label $top.bg -padx 40 -relief sunk -background $bgcolor
-    ${NS}::button $top.bgbut -text [mc "Background"] \
-	-command [list choosecolor bgcolor {} $top.bg [mc "background"] setbg]
-    grid x $top.bgbut $top.bg -sticky w
-    label $top.fg -padx 40 -relief sunk -background $fgcolor
-    ${NS}::button $top.fgbut -text [mc "Foreground"] \
-	-command [list choosecolor fgcolor {} $top.fg [mc "foreground"] setfg]
-    grid x $top.fgbut $top.fg -sticky w
-    label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
-    ${NS}::button $top.diffoldbut -text [mc "Diff: old lines"] \
-	-command [list choosecolor diffcolors 0 $top.diffold [mc "diff old lines"] \
-		      [list $ctext tag conf d0 -foreground]]
-    grid x $top.diffoldbut $top.diffold -sticky w
-    label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
-    ${NS}::button $top.diffnewbut -text [mc "Diff: new lines"] \
-	-command [list choosecolor diffcolors 1 $top.diffnew [mc "diff new lines"] \
-		      [list $ctext tag conf dresult -foreground]]
-    grid x $top.diffnewbut $top.diffnew -sticky w
-    label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
-    ${NS}::button $top.hunksepbut -text [mc "Diff: hunk header"] \
-	-command [list choosecolor diffcolors 2 $top.hunksep \
-		      [mc "diff hunk header"] \
-		      [list $ctext tag conf hunksep -foreground]]
-    grid x $top.hunksepbut $top.hunksep -sticky w
-    label $top.markbgsep -padx 40 -relief sunk -background $markbgcolor
-    ${NS}::button $top.markbgbut -text [mc "Marked line bg"] \
-	-command [list choosecolor markbgcolor {} $top.markbgsep \
-		      [mc "marked line background"] \
-		      [list $ctext tag conf omark -background]]
-    grid x $top.markbgbut $top.markbgsep -sticky w
-    label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
-    ${NS}::button $top.selbgbut -text [mc "Select bg"] \
-	-command [list choosecolor selectbgcolor {} $top.selbgsep [mc "background"] setselbg]
-    grid x $top.selbgbut $top.selbgsep -sticky w
+    lappend pages [prefspage_general $notebook] [mc "General"]
+    lappend pages [prefspage_colors $notebook] [mc "Colors"]
+    lappend pages [prefspage_fonts $notebook] [mc "Fonts"]
+    foreach {page title} $pages {
+	if {$use_notebook} {
+	    $notebook add $page -text $title
+	} else {
+	    set btn [${NS}::button $notebook.b_[string map {. X} $page] \
+			 -text $title -command [list raise $page]]
+	    $page configure -text $title
+	    grid $btn -row 0 -column [incr col] -sticky w
+	    grid $page -row 1 -column 0 -sticky news -columnspan 100
+	}
+    }
 
-    ${NS}::label $top.cfont -text [mc "Fonts: press to choose"]
-    grid $top.cfont - -sticky w -pady 10
-    mkfontdisp mainfont $top [mc "Main font"]
-    mkfontdisp textfont $top [mc "Diff display font"]
-    mkfontdisp uifont $top [mc "User interface font"]
+    if {!$use_notebook} {
+	grid columnconfigure $notebook 0 -weight 1
+	grid rowconfigure $notebook 1 -weight 1
+	raise [lindex $pages 0]
+    }
+
+    grid $notebook -sticky news -padx 2 -pady 2
+    grid rowconfigure $top 0 -weight 1
+    grid columnconfigure $top 0 -weight 1
 
     ${NS}::frame $top.buts
     ${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active
@@ -10936,7 +11000,7 @@ proc doprefs {} {
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
     grid $top.buts - - -pady 10 -sticky ew
     grid columnconfigure $top 2 -weight 1
-    bind $top  "focus $top.buts.ok"
+    bind $top  [list focus $top.buts.ok]
 }
 
 proc choose_extdiff {} {

From 52c8a98998817a5d6dff0a4be6405bdb9d012b02 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Mon, 30 Jan 2012 23:38:42 +0000
Subject: [PATCH 2884/3720] gitk: fix setting font display with new tabbed
 dialog layout.

The changes to the dialog window tree broke the preview of the selected
font on the button. This corrects that issue.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index dcae0a7547..a62f25d549 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10751,7 +10751,7 @@ proc fontok {} {
     if {$fontparam(slant) eq "italic"} {
 	lappend fontpref($f) "italic"
     }
-    set w $prefstop.$f
+    set w $prefstop.notebook.fonts.$f
     $w conf -text $fontparam(family) -font $fontpref($f)
 
     fontcan

From 4efc677ae87a081231f596b4904a193dd930ae26 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 3 Feb 2012 00:12:04 -0600
Subject: [PATCH 2885/3720] Teach 'git remote' that the config var
 branch.*.rebase can be 'interactive'

Signed-off-by: Johannes Schindelin 
---
 builtin/remote.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index f54a89adc7..025a8a2ca1 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -253,7 +253,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	int rebase;
+	enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
 };
 
 static struct string_list branch_list;
@@ -310,7 +310,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			}
 			string_list_append(&info->merge, xstrdup(value));
 		} else
-			info->rebase = git_config_bool(orig_key, value);
+			info->rebase = value && *value == 'i' ?
+				INTERACTIVE_REBASE :
+				(git_config_bool(orig_key, value) ?
+				 NORMAL_REBASE : NO_REBASE);
 	}
 	return 0;
 }
@@ -994,7 +997,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf("rebases onto remote %s\n", merge->items[0].string);
+		printf("rebases %sonto remote %s\n",
+			branch_info->rebase == INTERACTIVE_REBASE ?
+			"interactively " : "", merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf(" merges with remote %s\n", merge->items[0].string);

From 3870c4cddb30cc1049a76a06dbe84ff8fe22e681 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:28:37 +0100
Subject: [PATCH 2886/3720] git-gui: fix encoding in git-gui file browser

Assume git tree objects (i.e. output of git-ls-tree) are encoded in system
encoding, for display in the git-gui file browser.

Signed-off-by: Karsten Blees 
---
 git-gui/lib/browser.tcl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 0328338fda..4fca8fb13c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary -encoding binary
+	fconfigure $fd -blocking 0 -translation binary
 	fileevent $fd readable [cb _read $fd]
 }
 

From 75c554cf91c51779b42fefe3fbd47cff0b268c62 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:38:07 +0100
Subject: [PATCH 2887/3720] gitk: fix file name encoding in diff hunk headers

Decode file names from system encoding in all diff hunk header lines, not
just the first (i.e. print nice file names in 'rename from' / 'rename to' /
'Binary files' lines, too).

Signed-off-by: Karsten Blees 
---
 gitk-git/gitk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index a62f25d549..3660096db5 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7811,6 +7811,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
+	    set line [encoding convertfrom $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {

From d33520065de3be89ce9b4cd73ae2071046936845 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 12:09:11 +0200
Subject: [PATCH 2888/3720] Revert "Disable test on MinGW that challenges its
 bash quoting"

This reverts commit 8117ed6a2205c17823910749cf0391ad811bdfa9.

With "MinGW: disable CRT command line globbing" (a05e9a86), wildcard
expansion works as expected (handled by git, not the CRT).

Signed-off-by: Karsten Blees 
---
 t/t5505-remote.sh | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 1ad3551a6f..e8af615e6d 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -946,10 +946,7 @@ test_expect_success 'remote set-url --add bbb' '
 '
 
 test_expect_success 'remote set-url --delete .*' '
-	if test_have_prereq NOT_MINGW
-	then
-		test_must_fail git remote set-url --delete someremote .\*
-	fi &&
+	test_must_fail git remote set-url --delete someremote .\* &&
 	echo "YYY" >expect &&
 	echo baz >>expect &&
 	echo bbb >>expect &&

From dfb3eb3114dfd363eb5dd714ff9f74fcadc21d35 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 19:06:41 +0100
Subject: [PATCH 2889/3720] Revert "Windows: teach getenv to do a
 case-sensitive search"

This reverts commit df599e9612788b728ce43a03159b85f1fe624d6a.

As of 5e9637c6 "i18n: add infrastructure for translating Git with gettext",
eval_gettext uses MinGW envsubst.exe instead of git-sh-i18n--envsubst.exe
for variable substitution. This breaks git-submodule.sh messages and tests,
as envsubst.exe doesn't support case-sensitive environment lookup (the same
is true for almost everything on Windows, including MSys and Cygwin tools).

30a615ac "Windows/i18n: rename $path to prevent clashes with $PATH" renames
the conflicting variable in git-submodule.sh, so that it works on Windows
(i.e. with case-insensitive environment, regardless of the toolset).

Revert to the documented behaviour of case-insensitive environment on
Windows.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 952a2a6819..1135b4bb78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1182,31 +1182,14 @@ char **make_augmented_environ(const char *const *vars)
 }
 
 #undef getenv
-
-/*
- * The system's getenv looks up the name in a case-insensitive manner.
- * This version tries a case-sensitive lookup and falls back to
- * case-insensitive if nothing was found.  This is necessary because,
- * as a prominent example, CMD sets 'Path', but not 'PATH'.
- * Warning: not thread-safe.
- */
-static char *getenv_cs(const char *name)
-{
-	size_t len = strlen(name);
-	int i = lookup_env(environ, name, len);
-	if (i >= 0)
-		return environ[i] + len + 1;	/* skip past name and '=' */
-	return getenv(name);
-}
-
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv_cs(name);
+	char *result = getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv_cs("TMP");
+		result = getenv("TMP");
 		if (!result)
-			result = getenv_cs("TEMP");
+			result = getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */

From 7cb2dff786c9931d2a8325aacd307a24997013e4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:19:31 +0100
Subject: [PATCH 2890/3720] Revert "mingw.c: move definition of mingw_getenv
 down"

This reverts commit 06bc4b796ad69ba93f0a8c451368602e0553c2d3.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1135b4bb78..649c6857dd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -180,7 +180,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	vsnprintf(question, sizeof(question), format, args);
 	va_end(args);
 
-	if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
+	if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
 		retry_hook[1] = question;
 		return !run_command_v_opt(retry_hook, 0);
 	}
@@ -665,6 +665,23 @@ char *mingw_getcwd(char *pointer, int len)
 	return ret;
 }
 
+#undef getenv
+char *mingw_getenv(const char *name)
+{
+	char *result = getenv(name);
+	if (!result && !strcmp(name, "TMPDIR")) {
+		/* on Windows it is TMP and TEMP */
+		result = getenv("TMP");
+		if (!result)
+			result = getenv("TEMP");
+	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
+	return result;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -764,7 +781,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-	char *p, **path, *envpath = mingw_getenv("PATH");
+	char *p, **path, *envpath = getenv("PATH");
 	int i, n = 0;
 
 	if (!envpath || !*envpath)
@@ -1181,23 +1198,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-	char *result = getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
-		if (!result)
-			result = getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 9f90e5860f49a4b67acf6922d2de7e397e25d9d9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:24:19 +0100
Subject: [PATCH 2891/3720] Win32: Thread-safe windows console output

Winansi.c has many static variables that are accessed and modified from
the [v][f]printf / fputs functions overridden in the file. This may cause
multi threaded git commands that print to the console to produce corrupted
output or even crash.

Additionally, winansi.c doesn't override all functions that can be used to
print to the console (e.g. fwrite, write, fputc are missing), so that ANSI
escapes don't work properly for some git commands (e.g. git-grep).

Instead of doing ANSI emulation in just a few wrapped functions on top of
the IO API, let's plug into the IO system and take advantage of the thread
safety inherent to the IO system.

Redirect stdout and stderr to a pipe if they point to the console. A
background thread reads from the pipe, handles ANSI escape sequences and
UTF-8 to UTF-16 conversion, then writes to the console.

The pipe-based stdout and stderr replacements must be set to unbuffered, as
MSVCRT doesn't support line buffering and fully buffered streams are
inappropriate for console output.

Due to the byte-oriented pipe, ANSI escape sequences and multi-byte UTF-8
sequences can no longer be expected to arrive in one piece. Replace the
string-based ansi_emulate() with a simple stateful parser (this also fixes
colored diff hunk headers, which were broken as of commit 2efcc977).

Override isatty to return true for the pipes redirecting to the console.

Exec/spawn obtain the original console handle to pass to the next process
via winansi_get_osfhandle().

All other overrides are gone, the default stdio implementations work as
expected with the piped stdout/stderr descriptors.

Global variables are either initialized on startup (single threaded) or
exclusively modified by the background thread. Threads communicate through
the pipe, no further synchronization is necessary.

The background thread is terminated by disonnecting the pipe after flushing
the stdio and pipe buffers. This doesn't work for anonymous pipes (created
via CreatePipe), as DisconnectNamedPipe only works on the read end, which
discards remaining data. Thus we have to setup the pipe manually, with the
write end beeing the server (opened with CreateNamedPipe) and the read end
the client (opened with CreateFile).

Limitations: doesn't track reopened or duped file descriptors, i.e.:
- fdopen(1/2) returns fully buffered streams
- dup(1/2), dup2(1/2) returns normal pipe descriptors (i.e. isatty() =
  false, winansi_get_osfhandle won't return the original console handle)

Currently, only the git-format-patch command uses xfdopen(xdup(1)) (see
"realstdout" in builtin/log.c), but works well with these limitations.

Many thanks to Atsushi Nakagawa  for suggesting and
reviewing the thread-exit-mechanism.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c   |   9 +-
 compat/mingw.h   |  12 +-
 compat/winansi.c | 420 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 282 insertions(+), 159 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 649c6857dd..190e7b7681 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -917,9 +917,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	memset(&si, 0, sizeof(si));
 	si.cb = sizeof(si);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-	si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-	si.hStdError = (HANDLE) _get_osfhandle(fherr);
+	si.hStdInput = winansi_get_osfhandle(fhin);
+	si.hStdOutput = winansi_get_osfhandle(fhout);
+	si.hStdError = winansi_get_osfhandle(fherr);
 
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
@@ -1878,4 +1878,7 @@ void mingw_startup()
 	_setmode(_fileno(stdin), _O_BINARY);
 	_setmode(_fileno(stdout), _O_BINARY);
 	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
 }
diff --git a/compat/mingw.h b/compat/mingw.h
index 407bad231b..2683adcaf7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -288,14 +288,10 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-int winansi_vfprintf(FILE *stream, const char *format, va_list list);
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
-#define vfprintf winansi_vfprintf
+void winansi_init(void);
+int winansi_isatty(int fd);
+HANDLE winansi_get_osfhandle(int fd);
+#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index bec6713b74..a3e4d88295 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,18 +4,13 @@
 
 #undef NOGDI
 #include "../git-compat-util.h"
-#include 
 #include 
 #include 
 
 /*
  Functions to be wrapped:
 */
-#undef printf
-#undef fprintf
-#undef fputs
-#undef vfprintf
-/* TODO: write */
+#undef isatty
 
 /*
  ANSI codes used by git: m, K
@@ -28,7 +23,10 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
-static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hwrite1 = INVALID_HANDLE_VALUE, hwrite2 = INVALID_HANDLE_VALUE;
+static HANDLE hconsole1, hconsole2;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -44,27 +42,19 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void print_font_warning(void)
+static void warn_if_raster_font(void)
 {
-	warning("Your console font probably doesn\'t support Unicode. If "
-		"you experience strange characters in the output, consider "
-		"switching to a TrueType font such as Lucida Console!");
-}
-
-static void check_truetype_font(void)
-{
-	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't do this twice */
-	if (truetype_font_checked)
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
 		return;
-	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
+			GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);
@@ -73,8 +63,8 @@ static void check_truetype_font(void)
 	} else {
 		/* pre-Vista: check default console font in registry */
 		HKEY hkey;
-		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
-				KEY_READ, &hkey)) {
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+				0, KEY_READ, &hkey)) {
 			DWORD size = sizeof(fontFamily);
 			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
 					(LPVOID) &fontFamily, &size);
@@ -82,61 +72,63 @@ static void check_truetype_font(void)
 		}
 	}
 
-	if (!(fontFamily & TMPF_TRUETYPE))
-		atexit(print_font_warning);
+	if (!(fontFamily & TMPF_TRUETYPE)) {
+		const wchar_t *msg = L"\nWarning: Your console font probably "
+			L"doesn\'t support Unicode. If you experience strange "
+			L"characters in the output, consider switching to a "
+			L"TrueType font such as Lucida Console!\n";
+		WriteConsoleW(console, msg, wcslen(msg), NULL, NULL);
+	}
 }
 
-static int is_console(FILE *stream)
+static int is_console(int fd)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
 	HANDLE hcon;
 
 	static int initialized = 0;
 
-	/* use cached value if stream hasn't changed */
-	if (stream == last_stream)
-		return console != NULL;
-
-	last_stream = stream;
-	console = NULL;
-
-	/* get OS handle of the stream */
-	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	/* get OS handle of the file descriptor */
+	hcon = (HANDLE) _get_osfhandle(fd);
 	if (hcon == INVALID_HANDLE_VALUE)
 		return 0;
 
+	/* check if its a device (i.e. console, printer, serial port) */
+	if (GetFileType(hcon) != FILE_TYPE_CHAR)
+		return 0;
+
 	/* check if its a handle to a console output screen buffer */
 	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
+	/* initialize attributes */
 	if (!initialized) {
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
 	}
 
-	console = hcon;
 	return 1;
 }
 
-static int write_console(const char *str, size_t len)
-{
-	/* convert utf-8 to utf-16, write directly to console */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
-	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
-	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
 
+static void write_console(unsigned char *str, size_t len)
+{
+	/* only called from console_thread, so a static buffer will do */
+	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+
+	/* convert utf-8 to utf-16 */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
+			ARRAY_SIZE(wbuf));
+
+	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/*
-	 * if non-ascii characters are printed, check that the current console
-	 * font supports this
-	 */
+	/* remember if non-ascii characters are printed */
 	if (wlen != len)
-		check_truetype_font();
-
-	/* return original (utf-8 encoded) length */
-	return len;
+		non_ascii_used = 1;
 }
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
@@ -182,18 +174,13 @@ static void erase_in_line(void)
 		&dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-	const char *func;
-	size_t len = strspn(str, "0123456789;");
-	func = str + len;
-
-	switch (*func) {
+	int i;
+	switch (func) {
 	case 'm':
-		do {
-			long val = strtol(str, (char **)&str, 10);
-			switch (val) {
+		for (i = 0; i < paramlen; i++) {
+			switch (params[i]) {
 			case 0: /* reset */
 				attr = plain_attr;
 				negative = 0;
@@ -316,9 +303,7 @@ static const char *set_attr(const char *str)
 				/* Unsupported code */
 				break;
 			}
-			str++;
-		} while (*(str-1) == ';');
-
+		}
 		set_console_attr();
 		break;
 	case 'K':
@@ -328,112 +313,251 @@ static const char *set_attr(const char *str)
 		/* Unsupported code */
 		break;
 	}
-
-	return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+	TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-	int rv = 0;
-	const char *pos = str;
+	unsigned char buffer[BUFFER_SIZE];
+	DWORD bytes;
+	int start, end = 0, c, parampos = 0, state = TEXT;
+	int params[MAX_PARAMS];
 
-	fflush(stream);
+	while (1) {
+		/* read next chunk of bytes from the pipe */
+		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+				NULL)) {
+			/* exit if pipe has been closed or disconnected */
+			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+					GetLastError() == ERROR_BROKEN_PIPE)
+				break;
+			/* ignore other errors */
+			continue;
+		}
 
-	while (*pos) {
-		pos = strstr(str, "\033[");
-		if (pos) {
-			size_t len = pos - str;
+		/* scan the bytes and handle ANSI control codes */
+		bytes += end;
+		start = end = 0;
+		while (end < bytes) {
+			c = buffer[end++];
+			switch (state) {
+			case TEXT:
+				if (c == ESCAPE) {
+					/* print text seen so far */
+					if (end - 1 > start)
+						write_console(buffer + start,
+							end - 1 - start);
 
-			if (len) {
-				size_t out_len = write_console(str, len);
-				rv += out_len;
-				if (out_len < len)
-					return rv;
+					/* then start parsing escape sequence */
+					start = end - 1;
+					memset(params, 0, sizeof(params));
+					parampos = 0;
+					state = ESCAPE;
+				}
+				break;
+
+			case ESCAPE:
+				/* continue if "\033[", otherwise bail out */
+				state = (c == BRACKET) ? BRACKET : TEXT;
+				break;
+
+			case BRACKET:
+				/* parse [0-9;]* into array of parameters */
+				if (c >= '0' && c <= '9') {
+					params[parampos] *= 10;
+					params[parampos] += c - '0';
+				} else if (c == ';') {
+					/*
+					 * next parameter, bail out if out of
+					 * bounds
+					 */
+					parampos++;
+					if (parampos >= MAX_PARAMS)
+						state = TEXT;
+				} else {
+					/*
+					 * end of escape sequence, change
+					 * console attributes
+					 */
+					set_attr(c, params, parampos + 1);
+					start = end;
+					state = TEXT;
+				}
+				break;
+			}
+		}
+
+		/* print remaining text unless parsing an escape sequence */
+		if (state == TEXT && end > start) {
+			/* check for incomplete UTF-8 sequences and fix end */
+			if (buffer[end - 1] >= 0x80) {
+				if (buffer[end -1] >= 0xc0)
+					end--;
+				else if (end - 1 > start &&
+						buffer[end - 2] >= 0xe0)
+					end -= 2;
+				else if (end - 2 > start &&
+						buffer[end - 3] >= 0xf0)
+					end -= 3;
 			}
 
-			str = pos + 2;
-			rv += 2;
+			/* print remaining complete UTF-8 sequences */
+			if (end > start)
+				write_console(buffer + start, end - start);
 
-			pos = set_attr(str);
-			rv += pos - str;
-			str = pos;
+			/* move remaining bytes to the front */
+			if (end < bytes)
+				memmove(buffer, buffer + end, bytes - end);
+			end = bytes - end;
 		} else {
-			size_t len = strlen(str);
-			rv += write_console(str, len);
-			return rv;
+			/* all data has been consumed, mark buffer empty */
+			end = 0;
 		}
 	}
-	return rv;
+
+	/* check if the console font supports unicode */
+	warn_if_raster_font();
+
+	CloseHandle(hread);
+	return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-	int rv;
+	/* flush all streams */
+	_flushall();
 
-	if (!is_console(stream))
-		return fputs(str, stream);
+	/* signal console thread to exit */
+	FlushFileBuffers(hwrite);
+	DisconnectNamedPipe(hwrite);
 
-	rv = ansi_emulate(str, stream);
+	/* wait for console thread to copy remaining data */
+	WaitForSingleObject(hthread, INFINITE);
 
-	if (rv >= 0)
-		return 0;
+	/* cleanup handles... */
+	if (hwrite1 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite1);
+	if (hwrite2 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite2);
+	CloseHandle(hwrite);
+	CloseHandle(hthread);
+}
+
+static void die_lasterr(const char *fmt, ...)
+{
+	va_list params;
+	va_start(params, fmt);
+	errno = err_win_to_posix(GetLastError());
+	die_errno(fmt, params);
+	va_end(params);
+}
+
+static HANDLE duplicate_handle(HANDLE hnd)
+{
+	HANDLE hresult, hproc = GetCurrentProcess();
+	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+			DUPLICATE_SAME_ACCESS))
+		die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+	return hresult;
+}
+
+static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+{
+	/* get original console handle */
+	int fd = _fileno(stream);
+	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
+	if (hcon == INVALID_HANDLE_VALUE)
+		die_errno("_get_osfhandle(%i) failed", fd);
+
+	/* save a copy to phcon and console (used by the background thread) */
+	console = *phcon = duplicate_handle(hcon);
+
+	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
+	if (_dup2(new_fd, fd))
+		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+
+	/* no buffering, or stdout / stderr will be out of sync */
+	setbuf(stream, NULL);
+	return (HANDLE) _get_osfhandle(fd);
+}
+
+void winansi_init(void)
+{
+	int con1, con2, hwrite_fd;
+	char name[32];
+
+	/* check if either stdout or stderr is a console output screen buffer */
+	con1 = is_console(1);
+	con2 = is_console(2);
+	if (!con1 && !con2)
+		return;
+
+	/* create a named pipe to communicate with the console thread */
+	sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+	hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+	if (hwrite == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateNamedPipe failed");
+
+	hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (hread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateFile for named pipe failed");
+
+	/* start console spool thread on the pipe's read end */
+	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+	if (hthread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateThread(console_thread) failed");
+
+	/* schedule cleanup routine */
+	if (atexit(winansi_exit))
+		die_errno("atexit(winansi_exit) failed");
+
+	/* create a file descriptor for the write end of the pipe */
+	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
+	if (hwrite_fd == -1)
+		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
+
+	/* redirect stdout / stderr to the pipe */
+	if (con1)
+		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+	if (con2)
+		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
+
+	/* close pipe file descriptor (also closes the duped hwrite) */
+	close(hwrite_fd);
+}
+
+static int is_same_handle(HANDLE hnd, int fd)
+{
+	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
+}
+
+/*
+ * Return true if stdout / stderr is a pipe redirecting to the console.
+ */
+int winansi_isatty(int fd)
+{
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return 1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return 1;
 	else
-		return EOF;
+		return isatty(fd);
 }
 
-int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-	int len, rv;
-	char small_buf[256];
-	char *buf = small_buf;
-	va_list cp;
-
-	if (!is_console(stream))
-		goto abort;
-
-	va_copy(cp, list);
-	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-	va_end(cp);
-
-	if (len > sizeof(small_buf) - 1) {
-		buf = malloc(len + 1);
-		if (!buf)
-			goto abort;
-
-		len = vsnprintf(buf, len + 1, format, list);
-	}
-
-	rv = ansi_emulate(buf, stream);
-
-	if (buf != small_buf)
-		free(buf);
-	return rv;
-
-abort:
-	rv = vfprintf(stream, format, list);
-	return rv;
-}
-
-int winansi_fprintf(FILE *stream, const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stream, format, list);
-	va_end(list);
-
-	return rv;
-}
-
-int winansi_printf(const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stdout, format, list);
-	va_end(list);
-
-	return rv;
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return hconsole1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return hconsole2;
+	else
+		return (HANDLE) _get_osfhandle(fd);
 }

From c5d4ecfed65025c3bc9d08e37ebee4baa66034d6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:05:06 +0100
Subject: [PATCH 2892/3720] Win32: add Unicode conversion functions

Add Unicode conversion functions to convert between Windows native UTF-16LE
encoding to UTF-8 and back.

To support repositories with legacy-encoded file names, the UTF-8 to UTF-16
conversion function tries to create valid, unique file names even for
invalid UTF-8 byte sequences, so that these repositories can be checked out
without error.

The current implementation leaves invalid UTF-8 bytes in range 0xa0 - 0xff
as is (producing printable Unicode chars \u00a0 - \u00ff, equivalent to
ISO-8859-1), and converts 0x80 - 0x9f to hex-code (\u0080 - \u009f are
control chars).

The Windows MultiByteToWideChar API was not used as it either drops invalid
UTF-8 sequences (on Win2k/XP; producing non-unique or even empty file
names) or converts them to the replacement char \ufffd (Vista/7; causing
ERROR_INVALID_NAME in subsequent calls to file system APIs).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c |  85 ++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 190e7b7681..8ed43f9bf1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1859,6 +1859,91 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
diff --git a/compat/mingw.h b/compat/mingw.h
index 2683adcaf7..ddb228473b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -326,6 +326,110 @@ void mingw_mark_as_git_dir(const char *dir);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A replacement of main() that adds win32 specific initialization.
  */

From 19d1e75d58d772329372d453ead964c813bbc6b6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 21:28:22 +0100
Subject: [PATCH 2893/3720] Win32: Unicode file name support (except dirent)

Replaces Windows "ANSI" APIs dealing with file- or path names with their
Unicode equivalent, adding UTF-8/UTF-16LE conversion as necessary.

The dirent API (opendir/readdir/closedir) is updated in a separate commit.

Adds trivial wrappers for access, chmod and chdir.

Adds wrapper for mktemp (needed for both mkstemp and mkdtemp).

The simplest way to convert a repository with legacy-encoded (e.g. Cp1252)
file names to UTF-8 ist to checkout with an old msysgit version and
"git add --all & git commit" with the new version.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 210 ++++++++++++++++++++++++++++++++++---------------
 compat/mingw.h |  13 +++
 2 files changed, 158 insertions(+), 65 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8ed43f9bf1..5d5f30bd2c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "win32.h"
 #include 
+#include 
 #include "../strbuf.h"
 #include "../run-command.h"
 #include "../cache.h"
@@ -200,14 +201,16 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	}
 }
 
-#undef unlink
 int mingw_unlink(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
 	/* read-only files cannot be removed */
-	chmod(pathname, 0666);
-	while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
 		/*
@@ -223,43 +226,40 @@ int mingw_unlink(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = unlink(pathname);
+	       ret = _wunlink(wpathname);
 	return ret;
 }
 
-static int is_dir_empty(const char *path)
+static int is_dir_empty(const wchar_t *wpath)
 {
-	struct strbuf buf = STRBUF_INIT;
-	WIN32_FIND_DATAA findbuf;
+	WIN32_FIND_DATAW findbuf;
 	HANDLE handle;
-
-	strbuf_addf(&buf, "%s\\*", path);
-	handle = FindFirstFileA(buf.buf, &findbuf);
-	if (handle == INVALID_HANDLE_VALUE) {
-		strbuf_release(&buf);
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
 		return GetLastError() == ERROR_NO_MORE_FILES;
-	}
 
-	while (!strcmp(findbuf.cFileName, ".") ||
-			!strcmp(findbuf.cFileName, ".."))
-		if (!FindNextFile(handle, &findbuf)) {
-			strbuf_release(&buf);
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf))
 			return GetLastError() == ERROR_NO_MORE_FILES;
-		}
 	FindClose(handle);
-	strbuf_release(&buf);
 	return 0;
 }
 
-#undef rmdir
 int mingw_rmdir(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
-	while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
-		if (!is_dir_empty(pathname)) {
+		if (!is_dir_empty(wpathname)) {
 			errno = ENOTEMPTY;
 			break;
 		}
@@ -276,14 +276,14 @@ int mingw_rmdir(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = rmdir(pathname);
+	       ret = _wrmdir(wpathname);
 	return ret;
 }
 
-static int make_hidden(const char *path)
+static int make_hidden(const wchar_t *path)
 {
-	DWORD attribs = GetFileAttributes(path);
-	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+	DWORD attribs = GetFileAttributesW(path);
+	if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
 		return 0;
 	errno = err_win_to_posix(GetLastError());
 	return -1;
@@ -291,19 +291,23 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
-	    make_hidden(dir))
-		warning("Failed to make '%s' hidden", dir);
+	wchar_t wdir[MAX_PATH];
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
+		if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
+			warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
 		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
 		 "dotGitOnly" : "true"));
 }
 
-#undef mkdir
 int mingw_mkdir(const char *path, int mode)
 {
-	int ret = mkdir(path);
+	int ret;
+	wchar_t wpath[MAX_PATH];
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
 	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
 		/*
 		 * In Windows a file or dir starting with a dot is not
@@ -312,17 +316,17 @@ int mingw_mkdir(const char *path, int mode)
 		 */
 		const char *start = basename((char*)path);
 		if (*start == '.')
-			return make_hidden(path);
+			return make_hidden(wpath);
 	}
 	return ret;
 }
 
-#undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
 	va_list args;
 	unsigned mode;
 	int fd;
+	wchar_t wfilename[MAX_PATH];
 
 	va_start(args, oflags);
 	mode = va_arg(args, int);
@@ -331,10 +335,12 @@ int mingw_open (const char *filename, int oflags, ...)
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
 
-	fd = open(filename, oflags, mode);
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	fd = _wopen(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
-		DWORD attrs = GetFileAttributes(filename);
+		DWORD attrs = GetFileAttributesW(wfilename);
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
@@ -346,7 +352,7 @@ int mingw_open (const char *filename, int oflags, ...)
 		 * such a file is created.
 		 */
 		const char *start = basename((char*)filename);
-		if (*start == '.' && make_hidden(filename))
+		if (*start == '.' && make_hidden(wfilename))
 			warning("Could not mark '%s' as hidden.", filename);
 	}
 	return fd;
@@ -369,38 +375,69 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 	return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
-#undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = fopen(filename, otype);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfopen(wfilename, wotype);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
-#undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = freopen(filename, otype, stream);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -426,10 +463,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
  */
 static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
-	int err;
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
-	if (!(err = get_file_attr(file_name, &fdata))) {
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
 		buf->st_ino = 0;
 		buf->st_gid = 0;
 		buf->st_uid = 0;
@@ -442,8 +481,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-			WIN32_FIND_DATAA findbuf;
-			HANDLE handle = FindFirstFileA(file_name, &findbuf);
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
 			if (handle != INVALID_HANDLE_VALUE) {
 				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
 						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
@@ -462,7 +501,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		}
 		return 0;
 	}
-	errno = err;
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	default:
+		errno = ENOENT;
+		break;
+	}
 	return -1;
 }
 
@@ -551,16 +606,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
 {
 	FILETIME mft, aft;
 	int fh, rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
 	/* must have write permission */
-	DWORD attrs = GetFileAttributes(file_name);
+	attrs = GetFileAttributesW(wfilename);
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors here; open() will report them */
-		SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
 	}
 
-	if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+	if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
 		rc = -1;
 		goto revert_attrs;
 	}
@@ -583,7 +642,7 @@ revert_attrs:
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors again */
-		SetFileAttributes(file_name, attrs);
+		SetFileAttributesW(wfilename, attrs);
 	}
 	return rc;
 }
@@ -594,6 +653,18 @@ unsigned int sleep (unsigned int seconds)
 	return 0;
 }
 
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
 int mkstemp(char *template)
 {
 	char *filename = mktemp(template);
@@ -652,17 +723,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
 	return result;
 }
 
-#undef getcwd
 char *mingw_getcwd(char *pointer, int len)
 {
 	int i;
-	char *ret = getcwd(pointer, len);
-	if (!ret)
-		return ret;
+	wchar_t wpointer[MAX_PATH];
+	if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+		return NULL;
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
 	for (i = 0; pointer[i]; i++)
 		if (pointer[i] == '\\')
 			pointer[i] = '/';
-	return ret;
+	return pointer;
 }
 
 #undef getenv
@@ -1495,33 +1567,36 @@ int mingw_rename(const char *pold, const char *pnew)
 {
 	DWORD attrs, gle;
 	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+		return -1;
 
 	/*
 	 * Try native rename() first to get errno right.
 	 * It is based on MoveFile(), which cannot overwrite existing files.
 	 */
-	if (!rename(pold, pnew))
+	if (!_wrename(wpold, wpnew))
 		return 0;
 	if (errno != EEXIST)
 		return -1;
 repeat:
-	if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 		return 0;
 	/* TODO: translate more errors */
 	gle = GetLastError();
 	if (gle == ERROR_ACCESS_DENIED &&
-	    (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
 		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
 			errno = EISDIR;
 			return -1;
 		}
 		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
-		    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
-			if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 				return 0;
 			gle = GetLastError();
 			/* revert file attributes on failure */
-			SetFileAttributes(pnew, attrs);
+			SetFileAttributesW(wpnew, attrs);
 		}
 	}
 	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
@@ -1731,11 +1806,16 @@ void mingw_open_html(const char *unixpath)
 
 int link(const char *oldpath, const char *newpath)
 {
-	typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+	typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
 	static T create_hard_link = NULL;
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
 	if (!create_hard_link) {
 		create_hard_link = (T) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+			GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
 		if (!create_hard_link)
 			create_hard_link = (T)-1;
 	}
@@ -1743,7 +1823,7 @@ int link(const char *oldpath, const char *newpath)
 		errno = ENOSYS;
 		return -1;
 	}
-	if (!create_hard_link(newpath, oldpath, NULL)) {
+	if (!create_hard_link(wnewpath, woldpath, NULL)) {
 		errno = err_win_to_posix(GetLastError());
 		return -1;
 	}
diff --git a/compat/mingw.h b/compat/mingw.h
index ddb228473b..ea8c1f8993 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -182,6 +182,19 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 

From 2d98d6e26fae439d0a437b5e8ff0cc476b72d4ae Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:01:09 +0100
Subject: [PATCH 2894/3720] Win32: Unicode file name support (dirent)

Changes opendir/readdir to use Windows Unicode APIs and convert between
UTF-8/UTF-16.

Removes parameter checks that are already covered by xutftowcs_path. This
changes detection of ENAMETOOLONG from MAX_PATH - 2 to MAX_PATH (matching
is_dir_empty in mingw.c). If name + "/*" or the resulting absolute path is
too long, FindFirstFile fails and errno is set through err_win_to_posix.

Increases the size of dirent.d_name to accommodate the full
WIN32_FIND_DATA.cFileName converted to UTF-8 (UTF-16 to UTF-8 conversion
may grow by factor three in the worst case).

Signed-off-by: Karsten Blees 
---
 compat/win32/dirent.c | 30 ++++++++++--------------------
 compat/win32/dirent.h |  2 +-
 2 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 82a515c21b..52420ec7d4 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -6,10 +6,10 @@ struct DIR {
 	int dd_stat;          /* 0-based index */
 };
 
-static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
 {
-	/* copy file name from WIN32_FIND_DATA to dirent */
-	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+	/* convert UTF-16 name to UTF-8 */
+	xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
 
 	/* Set file type, based on WIN32_FIND_DATA */
 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -20,25 +20,15 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
 
 DIR *opendir(const char *name)
 {
-	char pattern[MAX_PATH];
-	WIN32_FIND_DATAA fdata;
+	wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
+	WIN32_FIND_DATAW fdata;
 	HANDLE h;
 	int len;
 	DIR *dir;
 
-	/* check that name is not NULL */
-	if (!name) {
-		errno = EINVAL;
+	/* convert name to UTF-16 and check length < MAX_PATH */
+	if ((len = xutftowcs_path(pattern, name)) < 0)
 		return NULL;
-	}
-	/* check that the pattern won't be too long for FindFirstFileA */
-	len = strlen(name);
-	if (len + 2 >= MAX_PATH) {
-		errno = ENAMETOOLONG;
-		return NULL;
-	}
-	/* copy name to temp buffer */
-	memcpy(pattern, name, len + 1);
 
 	/* append optional '/' and wildcard '*' */
 	if (len && !is_dir_sep(pattern[len - 1]))
@@ -47,7 +37,7 @@ DIR *opendir(const char *name)
 	pattern[len] = 0;
 
 	/* open find handle */
-	h = FindFirstFileA(pattern, &fdata);
+	h = FindFirstFileW(pattern, &fdata);
 	if (h == INVALID_HANDLE_VALUE) {
 		DWORD err = GetLastError();
 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
@@ -72,8 +62,8 @@ struct dirent *readdir(DIR *dir)
 	/* if first entry, dirent has already been set up by opendir */
 	if (dir->dd_stat) {
 		/* get next entry and convert from WIN32_FIND_DATA to dirent */
-		WIN32_FIND_DATAA fdata;
-		if (FindNextFileA(dir->dd_handle, &fdata)) {
+		WIN32_FIND_DATAW fdata;
+		if (FindNextFileW(dir->dd_handle, &fdata)) {
 			finddata2dirent(&dir->dd_dir, &fdata);
 		} else {
 			DWORD lasterr = GetLastError();
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 8838cd61fc..058207e4bf 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,7 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
-	char d_name[MAX_PATH];     /* file name */
+	char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
 };
 
 DIR *opendir(const char *dirname);

From 52b4755b1034f73298cfe0adbb92b66d25e3978d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 4 Feb 2012 21:54:36 +0100
Subject: [PATCH 2895/3720] Unicode file name support (gitk and git-gui)

Assumes file names in git tree objects are UTF-8 encoded.

On most unix systems, the system encoding (and thus the TCL system
encoding) will be UTF-8, so file names will be displayed correctly.

On Windows, it is impossible to set the system encoding to UTF-8. Changing
the TCL system encoding (via 'encoding system ...', e.g. in the startup
code) is explicitly discouraged by the TCL docs.

Change gitk and git-gui functions dealing with file names to always convert
from and to UTF-8.

Signed-off-by: Karsten Blees 
---
 git-gui/git-gui.sh      | 11 +++++++----
 git-gui/lib/browser.tcl |  2 +-
 git-gui/lib/index.tcl   |  6 +++---
 gitk-git/gitk           | 16 ++++++++--------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index a59020bcc5..e5038ddd12 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -533,6 +533,9 @@ proc git {args} {
 
 	_trace_exec [concat $opt $cmdp $args]
 	set result [eval exec $opt $cmdp $args]
+	if {[encoding system] != "utf-8"} {
+		set result [encoding convertfrom utf-8 [encoding convertto $result]]
+	}
 	if {$::_trace} {
 		puts stderr "< $result"
 	}
@@ -1087,7 +1090,7 @@ git-version proc _parse_config {arr_name args} {
 				[list git_read config] \
 				$args \
 				[list --null --list]]
-			fconfigure $fd_rc -translation binary
+			fconfigure $fd_rc -translation binary -encoding utf-8
 			set buf [read $fd_rc]
 			close $fd_rc
 		}
@@ -1652,7 +1655,7 @@ proc read_diff_index {fd after} {
 		set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			[lindex $i 4]? \
 			[list [lindex $i 0] [lindex $i 2]] \
 			[list]
@@ -1685,7 +1688,7 @@ proc read_diff_files {fd after} {
 		set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			?[lindex $i 4] \
 			[list] \
 			[list [lindex $i 0] [lindex $i 2]]
@@ -1708,7 +1711,7 @@ proc read_ls_others {fd after} {
 	set pck [split $buf_rlo "\0"]
 	set buf_rlo [lindex $pck end]
 	foreach p [lrange $pck 0 end-1] {
-		set p [encoding convertfrom $p]
+		set p [encoding convertfrom utf-8 $p]
 		if {[string index $p end] eq {/}} {
 			set p [string range $p 0 end-1]
 		}
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 4fca8fb13c..555db896f4 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary
+	fconfigure $fd -blocking 0 -translation binary -encoding utf-8
 	fileevent $fd readable [cb _read $fd]
 }
 
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdde21..6ca0a6e369 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -115,7 +115,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
 		set info [lindex $s 2]
 		if {$info eq {}} continue
 
-		puts -nonewline $fd "$info\t[encoding convertto $path]\0"
+		puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -186,7 +186,7 @@ proc write_update_index {fd pathList totalCnt batch after} {
 		?M {set new M_}
 		?? {continue}
 		}
-		puts -nonewline $fd "[encoding convertto $path]\0"
+		puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -247,7 +247,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
 		?M -
 		?T -
 		?D {
-			puts -nonewline $fd "[encoding convertto $path]\0"
+			puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 			display_file $path ?_
 		}
 		}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 3660096db5..f9e936d69e 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7288,7 +7288,7 @@ proc gettreeline {gtf id} {
 	if {[string index $fname 0] eq "\""} {
 	    set fname [lindex $fname 0]
 	}
-	set fname [encoding convertfrom $fname]
+	set fname [encoding convertfrom utf-8 $fname]
 	lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -7507,7 +7507,7 @@ proc gettreediffline {gdtf ids} {
 	    if {[string index $file 0] eq "\""} {
 		set file [lindex $file 0]
 	    }
-	    set file [encoding convertfrom $file]
+	    set file [encoding convertfrom utf-8 $file]
 	    if {$file ne [lindex $treediff end]} {
 		lappend treediff $file
 		lappend sublist $file
@@ -7656,7 +7656,7 @@ proc makediffhdr {fname ids} {
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -7690,7 +7690,7 @@ proc getblobdiffline {bdf ids} {
 	}
 	if {![string compare -length 5 "diff " $line]} {
 	    if {![regexp {^diff (--cc|--git) } $line m type]} {
-		set line [encoding convertfrom $line]
+		set line [encoding convertfrom utf-8 $line]
 		$ctext insert end "$line\n" hunksep
 		continue
 	    }
@@ -7737,7 +7737,7 @@ proc getblobdiffline {bdf ids} {
 	    makediffhdr $fname $ids
 
 	} elseif {![string compare -length 16 "* Unmerged path " $line]} {
-	    set fname [encoding convertfrom [string range $line 16 end]]
+	    set fname [encoding convertfrom utf-8 [string range $line 16 end]]
 	    $ctext insert end "\n"
 	    set curdiffstart [$ctext index "end - 1c"]
 	    lappend ctext_file_names $fname
@@ -7792,7 +7792,7 @@ proc getblobdiffline {bdf ids} {
 		if {[string index $fname 0] eq "\""} {
 		    set fname [lindex $fname 0]
 		}
-		set fname [encoding convertfrom $fname]
+		set fname [encoding convertfrom utf-8 $fname]
 		set i [lsearch -exact $treediffs($ids) $fname]
 		if {$i >= 0} {
 		    setinlist difffilestart $i $curdiffstart
@@ -7811,7 +7811,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
-	    set line [encoding convertfrom $line]
+	    set line [encoding convertfrom utf-8 $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {
@@ -11460,7 +11460,7 @@ proc cache_gitattr {attr pathlist} {
 	    foreach row [split $rlist "\n"] {
 		if {[regexp "(.*): $attr: (.*)" $row m path value]} {
 		    if {[string index $path 0] eq "\""} {
-			set path [encoding convertfrom [lindex $path 0]]
+			set path [encoding convertfrom utf-8 [lindex $path 0]]
 		    }
 		    set path_attr_cache($attr,$path) $value
 		}

From 95b74fc92be8d304616e1d7e629ef9017b09f3cf Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:27:53 +0100
Subject: [PATCH 2896/3720] Win32: Unicode arguments (outgoing)

Convert command line arguments from UTF-8 to UTF-16 when creating other
processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 5d5f30bd2c..de0a55fe84 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -955,9 +955,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFO si;
+	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
 	struct strbuf envblk, args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
 	unsigned flags;
 	BOOL ret;
 
@@ -993,6 +994,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	si.hStdOutput = winansi_get_osfhandle(fhout);
 	si.hStdError = winansi_get_osfhandle(fherr);
 
+	if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
 	if (prepend_cmd) {
@@ -1010,6 +1016,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			free(quoted);
 	}
 
+	wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
@@ -1031,12 +1041,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	}
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir, &si, &pi);
+	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
 	if (env)
 		strbuf_release(&envblk);
-	strbuf_release(&args);
+	free(wargs);
 
 	if (!ret) {
 		errno = ENOENT;

From ac3ea9ea461ee339ad76081f000901fb8074e5fa Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:28:27 +0100
Subject: [PATCH 2897/3720] Win32: Unicode arguments (incoming)

Convert command line arguments from UTF-16 to UTF-8 on startup.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index de0a55fe84..428c056009 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2040,10 +2040,41 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
  */
 int _CRT_glob = 0;
 
+typedef struct {
+	int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+		_startupinfo *si);
+
 void mingw_startup()
 {
-	/* copy executable name to argv[0] */
-	__argv[0] = xstrdup(_pgmptr);
+	int i, len, maxlen, argc;
+	char *buffer;
+	wchar_t **wenv, **wargv;
+	_startupinfo si;
+
+	/* get wide char arguments and environment */
+	si.newmode = 0;
+	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(_wpgmptr);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = xmalloc(maxlen);
+
+	/* convert command line arguments and environment to UTF-8 */
+	len = xwcstoutf(buffer, _wpgmptr, maxlen);
+	__argv[0] = xmemdupz(buffer, len);
+	for (i = 1; i < argc; i++) {
+		len = xwcstoutf(buffer, wargv[i], maxlen);
+		__argv[i] = xmemdupz(buffer, len);
+	}
+	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);

From 33630f38e2773158a67e023e0e2e0a800a7f9773 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:17:49 +0100
Subject: [PATCH 2898/3720] Win32: sync Unicode console output and file system

Use the same Unicode conversion functions for file names and console
conversions so that the file system and console output are in sync when
checking out legacy encoded repositories (i.e. with invalid UTF-8 file
names).

Signed-off-by: Karsten Blees 
---
 compat/winansi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a3e4d88295..9f95954390 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -120,8 +120,7 @@ static void write_console(unsigned char *str, size_t len)
 	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
 
 	/* convert utf-8 to utf-16 */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
-			ARRAY_SIZE(wbuf));
+	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);

From 288b6d51d3be5870b91478d47a781cb1c5692112 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:07:46 +0100
Subject: [PATCH 2899/3720] Win32: Unicode environment (outgoing)

Convert environment from UTF-8 to UTF-16 when creating other processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 428c056009..d78ac239e0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -957,9 +957,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 {
 	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
-	struct strbuf envblk, args;
-	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
-	unsigned flags;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 
 	/* Determine whether or not we are associated to a console */
@@ -976,7 +976,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * instead of CREATE_NO_WINDOW to make ssh
 		 * recognize that it has no console.
 		 */
-		flags = DETACHED_PROCESS;
+		flags |= DETACHED_PROCESS;
 	} else {
 		/* There is already a console. If we specified
 		 * DETACHED_PROCESS here, too, Windows would
@@ -984,7 +984,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * The same is true for CREATE_NO_WINDOW.
 		 * Go figure!
 		 */
-		flags = 0;
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
@@ -1023,6 +1022,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
+		int size = 0, wenvsz = 0, wenvpos = 0;
 
 		for (e = env; *e; e++)
 			count++;
@@ -1032,20 +1032,22 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
 		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
 
-		strbuf_init(&envblk, 0);
+		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
-			strbuf_addstr(&envblk, *e);
-			strbuf_addch(&envblk, '\0');
+			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
 		}
+		/* add final \0 terminator */
+		wenvblk[wenvpos] = 0;
 		free(sorted_env);
 	}
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
+		wenvblk, dir ? wdir : NULL, &si, &pi);
 
-	if (env)
-		strbuf_release(&envblk);
+	free(wenvblk);
 	free(wargs);
 
 	if (!ret) {

From c05ab35e8b07f8e442f7e100dc6935359cd22969 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 25 Apr 2011 23:32:27 +0100
Subject: [PATCH 2900/3720] Win32: Unicode environment (incoming)

Convert environment from UTF-16 to UTF-8 on startup.

No changes to getenv() are necessary, as the MSVCRT version is implemented
on top of char **environ.

However, putenv / _wputenv from MSVCRT no longer work, for two reasons:
1. they try to keep environ, _wenviron and the Win32 process environment
in sync, using the default system encoding instead of UTF-8 to convert
between charsets
2. msysgit and MSVCRT use different allocators, memory allocated in git
cannot be freed by the CRT and vice versa

Implement mingw_putenv using the env_setenv helper function from the
environment merge code.

Note that in case of memory allocation failure, putenv now dies with error
message (due to xrealloc) instead of failing with ENOMEM. As git assumes
setenv / putenv to always succeed, this prevents it from continuing with
incorrect settings.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index d78ac239e0..fe1d0de81f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1282,6 +1282,12 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -2064,6 +2070,11 @@ void mingw_startup()
 	maxlen = wcslen(_wpgmptr);
 	for (i = 1; i < argc; i++)
 		maxlen = max(maxlen, wcslen(wargv[i]));
+	for (i = 0; wenv[i]; i++)
+		maxlen = max(maxlen, wcslen(wenv[i]));
+
+	/* nedmalloc can't free CRT memory, allocate resizable environment list */
+	environ = xcalloc(i + 1, sizeof(char*));
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2076,6 +2087,10 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wargv[i], maxlen);
 		__argv[i] = xmemdupz(buffer, len);
 	}
+	for (i = 0; wenv[i]; i++) {
+		len = xwcstoutf(buffer, wenv[i], maxlen);
+		environ[i] = xmemdupz(buffer, len);
+	}
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
diff --git a/compat/mingw.h b/compat/mingw.h
index ea8c1f8993..af1574c435 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -200,6 +200,8 @@ char *mingw_getcwd(char *pointer, int len);
 
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
+int mingw_putenv(const char *namevalue);
+#define putenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 86eab614652782d2cd6b5c94503cb226ffd8663e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 20 Aug 2011 14:27:02 +0200
Subject: [PATCH 2901/3720] MinGW: disable legacy encoding tests

On Windows, all native APIs are Unicode-based. It is impossible to pass
legacy encoded byte arrays to a process via command line or environment
variables. Disable the tests that try to do so.

In t3901, most tests still work if we don't mess up the repository encoding
in setup, so don't switch to ISO-8859-1 on MinGW.

Note that i18n tests that do their encoding tricks via encoded files (such
as t3900) are not affected by this.

Signed-off-by: Karsten Blees 
---
 t/t3901-i18n-patch.sh | 19 +++++++++++--------
 t/t4201-shortlog.sh   |  6 +++---
 t/t8005-blame-i18n.sh |  8 ++++----
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 31a5770b34..55c8a2f576 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -54,10 +54,13 @@ test_expect_success setup '
 	git add yours &&
 	git commit -s -m "Second on side" &&
 
-	# the second one on the side branch is ISO-8859-1
-	git config i18n.commitencoding ISO8859-1 &&
-	# use author and committer name in ISO-8859-1 to match it.
-	. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+	if test_have_prereq NOT_MINGW
+	then
+		# the second one on the side branch is ISO-8859-1
+		git config i18n.commitencoding ISO8859-1 &&
+		# use author and committer name in ISO-8859-1 to match it.
+		. "$TEST_DIRECTORY"/t3901-8859-1.txt
+	fi &&
 	test_tick &&
 	echo Yet another >theirs &&
 	git add theirs &&
@@ -119,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
 	check_encoding 2
 '
 
-test_expect_success 'rebase (L/L)' '
+test_expect_success NOT_MINGW 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
 	git config i18n.commitencoding ISO8859-1 &&
 	git config i18n.logoutputencoding ISO8859-1 &&
@@ -131,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 	check_encoding 2 8859
 '
 
-test_expect_success 'rebase (L/U)' '
+test_expect_success NOT_MINGW 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
 	git config i18n.commitencoding ISO8859-1 &&
@@ -159,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/L)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
 	git config i18n.commitencoding ISO8859-1 &&
@@ -189,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/U)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6872ba1a42..48963811bf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
 	test_cmp expect log.predictable
 '
 
-test_expect_success 'shortlog wrapping' '
+test_expect_success NOT_MINGW 'shortlog wrapping' '
 	cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
 	test_cmp expect out
 '
 
-test_expect_success 'shortlog from non-git directory' '
+test_expect_success NOT_MINGW 'shortlog from non-git directory' '
 	git log HEAD >log &&
 	GIT_DIR=non-existing git shortlog -w out &&
 	test_cmp expect out
@@ -135,7 +135,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success 'shortlog encoding' '
+test_expect_success NOT_MINGW 'shortlog encoding' '
 	git reset --hard "$commit" &&
 	git config --unset i18n.commitencoding &&
 	echo 2 > a1 &&
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index cb390559f9..a6e73d0635 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.commitencoding' '
 	git blame --incremental file | \
 		egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.logoutputencoding' '
 	git config i18n.logoutputencoding eucJP &&
 	git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=UTF-8' '
 	git blame --incremental --encoding=UTF-8 file | \
 		egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=none' '
 	git blame --incremental --encoding=none file | \
 		egrep "^(author|summary) " > actual &&

From e3c19cbe158981719f207dbd69c62d961c5955bb Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:29:40 +0100
Subject: [PATCH 2902/3720] Win32: fix environment memory leaks

All functions that modify the environment have memory leaks.

Disable gitunsetenv in the Makefile and use env_setenv (via mingw_putenv)
instead (this frees removed environment entries).

Move xstrdup from env_setenv to make_augmented_environ, so that
mingw_putenv no longer copies the environment entries (according to POSIX
[1], "the string [...] shall become part of the environment"). This also
fixes the memory leak in gitsetenv, which expects a POSIX compliant putenv.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html

Note: This patch depends on taking control of char **environ and having
our own mingw_putenv (both introduced in "Win32: Unicode environment
(incoming)").

Signed-off-by: Karsten Blees 
---
 Makefile       |  2 --
 compat/mingw.c | 10 ++++++----
 compat/mingw.h |  1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 4c65206ea7..4dca0a8552 100644
--- a/Makefile
+++ b/Makefile
@@ -1150,7 +1150,6 @@ ifeq ($(uname_S),Windows)
 	NO_IPV6 = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
@@ -1247,7 +1246,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SYMLINK_HEAD = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index fe1d0de81f..bbd35d8bd4 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1255,14 +1255,14 @@ static char **env_setenv(char **env, const char *name)
 			for (i = 0; env[i]; i++)
 				;
 			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 			env[i+1] = NULL;
 		}
 	}
 	else {
 		free(env[i]);
 		if (*eq)
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 		else
 			for (; env[i]; i++)
 				env[i] = env[i+1];
@@ -1277,8 +1277,10 @@ char **make_augmented_environ(const char *const *vars)
 {
 	char **env = copy_environ();
 
-	while (*vars)
-		env = env_setenv(env, *vars++);
+	while (*vars) {
+		const char *v = *vars++;
+		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+	}
 	return env;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index af1574c435..ba21474515 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -202,6 +202,7 @@ char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 int mingw_putenv(const char *namevalue);
 #define putenv mingw_putenv
+#define unsetenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 3a0c2b32052810030d982328adff8b5aea64b791 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 23:42:09 +0100
Subject: [PATCH 2903/3720] Win32: unify environment case-sensitivity

The environment on Windows is case-insensitive. Some environment functions
(such as unsetenv and make_augmented_environ) have always used case-
sensitive comparisons instead, while others (getenv, putenv, sorting in
spawn*) were case-insensitive.

Prevent potential inconsistencies by using case-insensitive comparison in
lookup_env (used by putenv, unsetenv and make_augmented_environ).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bbd35d8bd4..bef2f3314e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1234,8 +1234,7 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 	int i;
 
 	for (i = 0; env[i]; i++) {
-		if (0 == strncmp(env[i], name, nmln)
-		    && '=' == env[i][nmln])
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
 			/* matches */
 			return i;
 	}

From 2c6e342a2aed0e3b1f5ad2a6dc9b48d27af7cfea Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:33:17 +0100
Subject: [PATCH 2904/3720] Win32: simplify internal mingw_spawn* APIs

The only public spawn function that needs to tweak the environment is
mingw_spawnvpe (called from start_command). Nevertheless, all internal
spawn* functions take an env parameter and needlessly pass the global
char **environ around. Remove the env parameter where it's not needed.

This removes the internal mingw_execve abstraction, which is no longer
needed.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bef2f3314e..311a1832d0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1077,10 +1077,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-			   int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -1122,7 +1121,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 	return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
 	const char *interpr = parse_interpreter(cmd);
 	char **path;
@@ -1140,7 +1139,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 		argv2 = xmalloc(sizeof(*argv) * (argc+1));
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-		pid = mingw_spawnve(prog, argv2, env, 1);
+		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -1155,13 +1154,13 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 	return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+void mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
-	if (!try_shell_exec(cmd, argv, (char **)env)) {
+	if (!try_shell_exec(cmd, argv)) {
 		int pid, status;
 
-		pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
 			return;
 		if (waitpid(pid, &status, 0) < 0)
@@ -1176,7 +1175,7 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	char *prog = path_lookup(cmd, path, 0);
 
 	if (prog) {
-		mingw_execve(prog, argv, environ);
+		mingw_execv(prog, argv);
 		free(prog);
 	} else
 		errno = ENOENT;
@@ -1184,11 +1183,6 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	free_path_split(path);
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
-{
-	mingw_execve(cmd, argv, environ);
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
 	if (pid > 0 && sig == SIGTERM) {

From 9fe227aa15bcebb49a9d84728969124c9616868b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:05:04 +0100
Subject: [PATCH 2905/3720] Win32: move environment functions

Move environment helper functions up so that they can be reused by
mingw_getenv and mingw_spawnve_fd in subsequent patches.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 106 ++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 311a1832d0..0c406669df 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,6 +737,53 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
+static int env_compare(const void *a, const void *b)
+{
+	char *const *ea = a;
+	char *const *eb = b;
+	return strcasecmp(*ea, *eb);
+}
+
+static int lookup_env(char **env, const char *name, size_t nmln)
+{
+	int i;
+
+	for (i = 0; env[i]; i++) {
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
+			/* matches */
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * If name contains '=', then sets the variable, otherwise it unsets it
+ */
+static char **env_setenv(char **env, const char *name)
+{
+	char *eq = strchrnul(name, '=');
+	int i = lookup_env(env, name, eq-name);
+
+	if (i < 0) {
+		if (*eq) {
+			for (i = 0; env[i]; i++)
+				;
+			env = xrealloc(env, (i+2)*sizeof(*env));
+			env[i] = (char*) name;
+			env[i+1] = NULL;
+		}
+	}
+	else {
+		free(env[i]);
+		if (*eq)
+			env[i] = (char*) name;
+		else
+			for (; env[i]; i++)
+				env[i] = env[i+1];
+	}
+	return env;
+}
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -754,6 +801,12 @@ char *mingw_getenv(const char *name)
 	return result;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -936,13 +989,6 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
-static int env_compare(const void *a, const void *b)
-{
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
-}
-
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1223,46 +1269,6 @@ void free_environ(char **env)
 	free(env);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
-{
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
-	}
-	return -1;
-}
-
-/*
- * If name contains '=', then sets the variable, otherwise it unsets it
- */
-static char **env_setenv(char **env, const char *name)
-{
-	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
-
-	if (i < 0) {
-		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
-		}
-	}
-	else {
-		free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-	}
-	return env;
-}
-
 /*
  * Copies global environ and adjusts variables as specified by vars.
  */
@@ -1277,12 +1283,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-int mingw_putenv(const char *namevalue)
-{
-	environ = env_setenv(environ, namevalue);
-	return 0;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 69d8e9f64091c64a0dddd9e2e996ddab7d4fd58c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Wed, 5 Oct 2011 22:01:46 +0200
Subject: [PATCH 2906/3720] Win32: unify environment function names

Environment helper functions use random naming ('env' prefix or suffix or
both, with or without '_'). Change to POSIX naming scheme ('env' suffix,
no '_').

Env_setenv has more in common with putenv than setenv. Change to do_putenv.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0c406669df..e5d8c6a438 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,14 +737,14 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int env_compare(const void *a, const void *b)
+static int compareenv(const void *a, const void *b)
 {
 	char *const *ea = a;
 	char *const *eb = b;
 	return strcasecmp(*ea, *eb);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
+static int lookupenv(char **env, const char *name, size_t nmln)
 {
 	int i;
 
@@ -759,10 +759,10 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **env_setenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name)
 {
 	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
+	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
@@ -803,7 +803,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = env_setenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue);
 	return 0;
 }
 
@@ -1076,7 +1076,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		/* environment must be sorted */
 		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
 
 		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
@@ -1278,7 +1278,7 @@ char **make_augmented_environ(const char *const *vars)
 
 	while (*vars) {
 		const char *v = *vars++;
-		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
 	}
 	return env;
 }

From 57717ef96f536dfcf3e443d8ebc7219ca234d04f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:31:57 +0100
Subject: [PATCH 2907/3720] Win32: factor out environment block creation

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 55 +++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e5d8c6a438..be381573f1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -989,6 +989,36 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
+/*
+ * Create environment block suitable for CreateProcess.
+ */
+static wchar_t *make_environment_block(char **env)
+{
+	wchar_t *wenvblk = NULL;
+	int count = 0;
+	char **e, **tmpenv;
+	int size = 0, wenvsz = 0, wenvpos = 0;
+
+	for (e = env; *e; e++)
+		count++;
+
+	/* environment must be sorted */
+	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+
+	/* create environment block from temporary environment */
+	for (e = tmpenv; *e; e++) {
+		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+	}
+	/* add final \0 terminator */
+	wenvblk[wenvpos] = 0;
+	free(tmpenv);
+	return wenvblk;
+}
+
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1065,29 +1095,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env) {
-		int count = 0;
-		char **e, **sorted_env;
-		int size = 0, wenvsz = 0, wenvpos = 0;
-
-		for (e = env; *e; e++)
-			count++;
-
-		/* environment must be sorted */
-		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
-		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
-
-		/* create environment block from temporary environment */
-		for (e = sorted_env; *e; e++) {
-			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
-			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
-		}
-		/* add final \0 terminator */
-		wenvblk[wenvpos] = 0;
-		free(sorted_env);
-	}
+	if (env)
+		wenvblk = make_environment_block(env);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,

From 89d642a086a2d8a02e00edfa909d0167face069b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:57:14 +0100
Subject: [PATCH 2908/3720] Win32: don't copy the environment twice when
 spawning child processes

When spawning child processes via start_command(), the environment and all
environment entries are copied twice. First by make_augmented_environ /
copy_environ to merge with child_process.env. Then a second time by
make_environment_block to create a sorted environment block string as
required by CreateProcess.

Move the merge logic to make_environment_block so that we only need to copy
the environment once. This changes semantics of the env parameter: it now
expects a delta (such as child_process.env) rather than a full environment.
This is not a problem as the parameter is only used by start_command()
(all other callers previously passed char **environ, and now pass NULL).

The merge logic no longer xstrdup()s the environment strings, so do_putenv
must not free them. Add a parameter to distinguish this from normal putenv.

Remove the now unused make_augmented_environ / free_environ API.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 74 ++++++++++++++++----------------------------------
 compat/mingw.h |  6 ----
 run-command.c  | 10 ++-----
 3 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index be381573f1..9a0b39a47e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -759,7 +759,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **do_putenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
@@ -774,7 +774,8 @@ static char **do_putenv(char **env, const char *name)
 		}
 	}
 	else {
-		free(env[i]);
+		if (free_old)
+			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
 		else
@@ -803,7 +804,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue, 1);
 	return 0;
 }
 
@@ -990,21 +991,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 }
 
 /*
- * Create environment block suitable for CreateProcess.
+ * Create environment block suitable for CreateProcess. Merges current
+ * process environment and the supplied environment changes.
  */
-static wchar_t *make_environment_block(char **env)
+static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
 	int count = 0;
 	char **e, **tmpenv;
 	int size = 0, wenvsz = 0, wenvpos = 0;
 
-	for (e = env; *e; e++)
+	while (environ[count])
 		count++;
 
-	/* environment must be sorted */
+	/* copy the environment */
 	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+
+	/* merge supplied environment changes into the temporary environment */
+	for (e = deltaenv; e && *e; e++)
+		tmpenv = do_putenv(tmpenv, *e, 0);
+
+	/* environment must be sorted */
+	for (count = 0; tmpenv[count]; )
+		count++;
 	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
 
 	/* create environment block from temporary environment */
@@ -1027,7 +1037,7 @@ struct pinfo_t {
 struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
-static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
@@ -1095,8 +1105,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env)
-		wenvblk = make_environment_block(env);
+	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1134,10 +1143,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
 static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 		     const char *dir,
 		     int fhin, int fhout, int fherr)
 {
@@ -1161,14 +1170,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 				pid = -1;
 			}
 			else {
-				pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
 						       fhin, fhout, fherr);
 				free(iprog);
 			}
 			argv[0] = argv0;
 		}
 		else
-			pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
 					       fhin, fhout, fherr);
 		free(prog);
 	}
@@ -1257,41 +1266,6 @@ int mingw_kill(pid_t pid, int sig)
 	return -1;
 }
 
-static char **copy_environ(void)
-{
-	char **env;
-	int i = 0;
-	while (environ[i])
-		i++;
-	env = xmalloc((i+1)*sizeof(*env));
-	for (i = 0; environ[i]; i++)
-		env[i] = xstrdup(environ[i]);
-	env[i] = NULL;
-	return env;
-}
-
-void free_environ(char **env)
-{
-	int i;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-/*
- * Copies global environ and adjusts variables as specified by vars.
- */
-char **make_augmented_environ(const char *const *vars)
-{
-	char **env = copy_environ();
-
-	while (*vars) {
-		const char *v = *vars++;
-		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
-	}
-	return env;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
diff --git a/compat/mingw.h b/compat/mingw.h
index ba21474515..04b6523255 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -335,12 +335,6 @@ void mingw_open_html(const char *path);
 void mingw_mark_as_git_dir(const char *dir);
 #define mark_as_git_dir mingw_mark_as_git_dir
 
-/*
- * helpers
- */
-
-char **make_augmented_environ(const char *const *vars);
-void free_environ(char **env);
 
 /**
  * Converts UTF-8 encoded string to UTF-16LE.
diff --git a/run-command.c b/run-command.c
index 1db8abf984..6d0dc3da91 100644
--- a/run-command.c
+++ b/run-command.c
@@ -381,7 +381,6 @@ fail_pipe:
 {
 	int fhin = 0, fhout = 1, fherr = 2;
 	const char **sargv = cmd->argv;
-	char **env = environ;
 
 	if (cmd->no_stdin)
 		fhin = open("/dev/null", O_RDWR);
@@ -406,25 +405,20 @@ fail_pipe:
 	else if (cmd->out > 1)
 		fhout = dup(cmd->out);
 
-	if (cmd->env)
-		env = make_augmented_environ(cmd->env);
-
 	if (cmd->git_cmd) {
 		cmd->argv = prepare_git_cmd(cmd->argv);
 	} else if (cmd->use_shell) {
 		cmd->argv = prepare_shell_cmd(cmd->argv);
 	}
 
-	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
-				  fhin, fhout, fherr);
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
 	failed_errno = errno;
 	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 		error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 	if (cmd->clean_on_exit && cmd->pid >= 0)
 		mark_child_for_cleanup(cmd->pid);
 
-	if (cmd->env)
-		free_environ(env);
 	if (cmd->git_cmd)
 		free(cmd->argv);
 

From 4edc99242baf681ca5fb74028123906908d0cbcd Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:00:35 +0100
Subject: [PATCH 2909/3720] Win32: reduce environment array reallocations

Move environment array reallocation from do_putenv to the respective
callers. Keep track of the environment size in a global variable. Use
ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a
sufficiently sized environment array in make_environment_block to prevent
reallocations.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 60 ++++++++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9a0b39a47e..2d984bd8d3 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -758,19 +758,19 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
+ * Size includes the terminating NULL. Env must have room for size + 1 entries
+ * (in case of insert). Returns the new size. Optionally frees removed entries.
  */
-static char **do_putenv(char **env, const char *name, int free_old)
+static int do_putenv(char **env, const char *name, int size, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
+			env[size - 1] = (char*) name;
+			env[size] = NULL;
+			size++;
 		}
 	}
 	else {
@@ -778,13 +778,20 @@ static char **do_putenv(char **env, const char *name, int free_old)
 			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
-		else
+		else {
 			for (; env[i]; i++)
 				env[i] = env[i+1];
+			size--;
+		}
 	}
-	return env;
+	return size;
 }
 
+/* used number of elements of environ array, including terminating NULL */
+static int environ_size = 0;
+/* allocated size of environ array, in bytes */
+static int environ_alloc = 0;
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -804,7 +811,8 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue, 1);
+	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
+	environ_size = do_putenv(environ, namevalue, environ_size, 1);
 	return 0;
 }
 
@@ -997,31 +1005,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
-	int count = 0;
-	char **e, **tmpenv;
-	int size = 0, wenvsz = 0, wenvpos = 0;
+	char **tmpenv;
+	int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
 
-	while (environ[count])
-		count++;
+	while (deltaenv && deltaenv[i])
+		i++;
 
-	/* copy the environment */
-	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+	/* copy the environment, leaving space for changes */
+	tmpenv = xmalloc((size + i) * sizeof(char*));
+	memcpy(tmpenv, environ, size * sizeof(char*));
 
 	/* merge supplied environment changes into the temporary environment */
-	for (e = deltaenv; e && *e; e++)
-		tmpenv = do_putenv(tmpenv, *e, 0);
+	for (i = 0; deltaenv && deltaenv[i]; i++)
+		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
 	/* environment must be sorted */
-	for (count = 0; tmpenv[count]; )
-		count++;
-	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
 
 	/* create environment block from temporary environment */
-	for (e = tmpenv; *e; e++) {
-		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+	for (i = 0; tmpenv[i]; i++) {
+		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
 		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+		wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
 	}
 	/* add final \0 terminator */
 	wenvblk[wenvpos] = 0;
@@ -2052,7 +2057,9 @@ void mingw_startup()
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
 	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = xcalloc(i + 1, sizeof(char*));
+	environ = NULL;
+	environ_size = i + 1;
+	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2069,6 +2076,7 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wenv[i], maxlen);
 		environ[i] = xmemdupz(buffer, len);
 	}
+	environ[i] = NULL;
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */

From 857fbc9375a112b7d3b3aff5882b9ac984995c18 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:30:02 +0100
Subject: [PATCH 2910/3720] Win32: keep the environment sorted

The Windows environment is sorted, keep it that way for O(log n)
environment access.

Change compareenv to compare only the keys, so that it can be used to
find an entry irrespective of the value.

Change lookupenv to binary seach for an entry. Return one's complement of
the insert position if not found (libc's bsearch returns NULL).

Replace MSVCRT's getenv with a minimal do_getenv based on the binary search
function.

Change do_putenv to insert new entries at the correct position. Simplify
the function by swapping if conditions and using memmove instead of for
loops.

Move qsort from make_environment_block to mingw_startup. We still need to
sort on startup to make sure that the environment is sorted according to
our compareenv function (while Win32 / CreateProcess requires the
environment block to be sorted case-insensitively, CreateProcess currently
doesn't enforce this, and some applications such as bash just don't care).

Note that environment functions are _not_ thread-safe and are not required
to be so by POSIX, the application is responsible for synchronizing access
to the environment. MSVCRT's getenv and our new getenv implementation are
better than that in that they are thread-safe with respect to other getenv
calls as long as the environment is not modified. Git's indiscriminate use
of getenv in background threads currently requires this property.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 98 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 62 insertions(+), 36 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2d984bd8d3..b569faf0b0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,23 +737,42 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int compareenv(const void *a, const void *b)
+/*
+ * Compare environment entries by key (i.e. stopping at '=' or '\0').
+ */
+static int compareenv(const void *v1, const void *v2)
 {
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
+	const char *e1 = *(const char**)v1;
+	const char *e2 = *(const char**)v2;
+
+	for (;;) {
+		int c1 = *e1++;
+		int c2 = *e2++;
+		c1 = (c1 == '=') ? 0 : tolower(c1);
+		c2 = (c2 == '=') ? 0 : tolower(c2);
+		if (c1 > c2)
+			return 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 == 0)
+			return 0;
+	}
 }
 
-static int lookupenv(char **env, const char *name, size_t nmln)
+static int bsearchenv(char **env, const char *name, size_t size)
 {
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
+	unsigned low = 0, high = size;
+	while (low < high) {
+		unsigned mid = low + ((high - low) >> 1);
+		int cmp = compareenv(&env[mid], &name);
+		if (cmp < 0)
+			low = mid + 1;
+		else if (cmp > 0)
+			high = mid;
+		else
+			return mid;
 	}
-	return -1;
+	return ~low; /* not found, return 1's complement of insert position */
 }
 
 /*
@@ -763,26 +782,24 @@ static int lookupenv(char **env, const char *name, size_t nmln)
  */
 static int do_putenv(char **env, const char *name, int size, int free_old)
 {
-	char *eq = strchrnul(name, '=');
-	int i = lookupenv(env, name, eq-name);
+	int i = bsearchenv(env, name, size - 1);
 
-	if (i < 0) {
-		if (*eq) {
-			env[size - 1] = (char*) name;
-			env[size] = NULL;
+	/* optionally free removed / replaced entry */
+	if (i >= 0 && free_old)
+		free(env[i]);
+
+	if (strchr(name, '=')) {
+		/* if new value ('key=value') is specified, insert or replace entry */
+		if (i < 0) {
+			i = ~i;
+			memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
 			size++;
 		}
-	}
-	else {
-		if (free_old)
-			free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else {
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-			size--;
-		}
+		env[i] = (char*) name;
+	} else if (i >= 0) {
+		/* otherwise ('key') remove existing entry */
+		size--;
+		memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
 	}
 	return size;
 }
@@ -792,15 +809,24 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-#undef getenv
+static char *do_getenv(const char *name)
+{
+	char *value;
+	int pos = bsearchenv(environ, name, environ_size - 1);
+	if (pos < 0)
+		return NULL;
+	value = strchr(environ[pos], '=');
+	return value ? &value[1] : NULL;
+}
+
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv(name);
+	char *result = do_getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
+		result = do_getenv("TMP");
 		if (!result)
-			result = getenv("TEMP");
+			result = do_getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */
@@ -1019,9 +1045,6 @@ static wchar_t *make_environment_block(char **deltaenv)
 	for (i = 0; deltaenv && deltaenv[i]; i++)
 		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
-	/* environment must be sorted */
-	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
-
 	/* create environment block from temporary environment */
 	for (i = 0; tmpenv[i]; i++) {
 		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
@@ -2079,6 +2102,9 @@ void mingw_startup()
 	environ[i] = NULL;
 	free(buffer);
 
+	/* sort environment for O(log n) getenv / putenv */
+	qsort(environ, i, sizeof(char*), compareenv);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From e92cda2234d42e19970eb03f97064d8c1a7f0070 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:35:26 +0100
Subject: [PATCH 2911/3720] Win32: patch Windows environment on startup

Fix Windows specific environment settings on startup rather than checking
for special values on every getenv call.

As a side effect, this makes the patched environment (i.e. with properly
initialized TMPDIR and TERM) available to child processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index b569faf0b0..183a2a4558 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -809,7 +809,7 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-static char *do_getenv(const char *name)
+char *mingw_getenv(const char *name)
 {
 	char *value;
 	int pos = bsearchenv(environ, name, environ_size - 1);
@@ -819,22 +819,6 @@ static char *do_getenv(const char *name)
 	return value ? &value[1] : NULL;
 }
 
-char *mingw_getenv(const char *name)
-{
-	char *result = do_getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = do_getenv("TMP");
-		if (!result)
-			result = do_getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 int mingw_putenv(const char *namevalue)
 {
 	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
@@ -2105,6 +2089,21 @@ void mingw_startup()
 	/* sort environment for O(log n) getenv / putenv */
 	qsort(environ, i, sizeof(char*), compareenv);
 
+	/* fix Windows specific environment settings */
+
+	/* on Windows it is TMP and TEMP */
+	if (!getenv("TMPDIR")) {
+		const char *tmp = getenv("TMP");
+		if (!tmp)
+			tmp = getenv("TEMP");
+		if (tmp)
+			setenv("TMPDIR", tmp, 1);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "winansi", 1);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 5d22f812d426103a29dcce50db47e5274ebaf67b Mon Sep 17 00:00:00 2001
From: Jeff King 
Date: Mon, 6 Feb 2012 04:54:04 -0500
Subject: [PATCH 2912/3720] config: add include directive

It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).

This patch introduces an include directive for config files.
It looks like:

  [include]
    path = /path/to/file

This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).

The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.

Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:

  1. Parsing of other config-like files, like .gitmodules.
     There isn't a real need, and I'd rather be conservative
     and avoid unnecessary incompatibility or confusion.

  2. Reading single files via "git config". This is for two
     reasons:

       a. backwards compatibility with scripts looking at
          config-like files.

       b. inspection of a specific file probably means you
	  care about just what's in that file, not a general
          lookup for "do we have this value anywhere at
	  all". If that is not the case, the caller can
	  always specify "--includes".

  3. Writing files via "git config"; we want to treat
     include.* variables as literal items to be copied (or
     modified), and not expand them. So "git config
     --unset-all foo.bar" would operate _only_ on
     .git/config, not any of its included files (just as it
     also does not operate on ~/.gitconfig).

Signed-off-by: Jeff King 
Signed-off-by: Junio C Hamano 
---
 Documentation/config.txt               |  15 +++
 Documentation/git-config.txt           |   5 +
 Documentation/technical/api-config.txt |  22 +++++
 builtin/config.c                       |  31 ++++--
 cache.h                                |   8 ++
 config.c                               |  69 +++++++++++++-
 t/t1305-config-include.sh              | 126 +++++++++++++++++++++++++
 7 files changed, 268 insertions(+), 8 deletions(-)
 create mode 100755 t/t1305-config-include.sh

diff --git a/Documentation/config.txt b/Documentation/config.txt
index abeb82b2c6..e55dae1806 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -84,6 +84,17 @@ customary UNIX fashion.
 
 Some variables may require a special value format.
 
+Includes
+~~~~~~~~
+
+You can include one config file from another by setting the special
+`include.path` variable to the name of the file to be included. The
+included file is expanded immediately, as if its contents had been
+found at the location of the include directive. If the value of the
+`include.path` variable is a relative path, the path is considered to be
+relative to the configuration file in which the include directive was
+found. See below for examples.
+
 Example
 ~~~~~~~
 
@@ -106,6 +117,10 @@ Example
 		gitProxy="ssh" for "kernel.org"
 		gitProxy=default-proxy ; for the rest
 
+	[include]
+		path = /path/to/foo.inc ; include by absolute path
+		path = foo ; expand "foo" relative to the current file
+
 Variables
 ~~~~~~~~~
 
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index e7ecf5d803..aa8303b1ad 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -178,6 +178,11 @@ See also <>.
 	Opens an editor to modify the specified config file; either
 	'--system', '--global', or repository (default).
 
+--includes::
+--no-includes::
+	Respect `include.*` directives in config files when looking up
+	values. Defaults to on.
+
 [[FILES]]
 FILES
 -----
diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
index f428c5c486..c60b6b3c93 100644
--- a/Documentation/technical/api-config.txt
+++ b/Documentation/technical/api-config.txt
@@ -95,6 +95,28 @@ string is given, prints an error message and returns -1.
 Similar to `git_config_string`, but expands `~` or `~user` into the
 user's home directory when found at the beginning of the path.
 
+Include Directives
+------------------
+
+By default, the config parser does not respect include directives.
+However, a caller can use the special `git_config_include` wrapper
+callback to support them. To do so, you simply wrap your "real" callback
+function and data pointer in a `struct config_include_data`, and pass
+the wrapper to the regular config-reading functions. For example:
+
+-------------------------------------------
+int read_file_with_include(const char *file, config_fn_t fn, void *data)
+{
+	struct config_include_data inc = CONFIG_INCLUDE_INIT;
+	inc.fn = fn;
+	inc.data = data;
+	return git_config_from_file(git_config_include, file, &inc);
+}
+-------------------------------------------
+
+`git_config` respects includes automatically. The lower-level
+`git_config_from_file` does not.
+
 Writing Config Files
 --------------------
 
diff --git a/builtin/config.c b/builtin/config.c
index d35c06ae51..09bf778168 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -25,6 +25,7 @@ static const char *given_config_file;
 static int actions, types;
 static const char *get_color_slot, *get_colorbool_slot;
 static int end_null;
+static int respect_includes = -1;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -74,6 +75,7 @@ static struct option builtin_config_options[] = {
 	OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH),
 	OPT_GROUP("Other"),
 	OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
+	OPT_BOOL(0, "includes", &respect_includes, "respect include directives on lookup"),
 	OPT_END(),
 };
 
@@ -161,6 +163,9 @@ static int get_value(const char *key_, const char *regex_)
 	int ret = -1;
 	char *global = NULL, *repo_config = NULL;
 	const char *system_wide = NULL, *local;
+	struct config_include_data inc = CONFIG_INCLUDE_INIT;
+	config_fn_t fn;
+	void *data;
 
 	local = config_exclusive_filename;
 	if (!local) {
@@ -213,19 +218,28 @@ static int get_value(const char *key_, const char *regex_)
 		}
 	}
 
+	fn = show_config;
+	data = NULL;
+	if (respect_includes) {
+		inc.fn = fn;
+		inc.data = data;
+		fn = git_config_include;
+		data = &inc;
+	}
+
 	if (do_all && system_wide)
-		git_config_from_file(show_config, system_wide, NULL);
+		git_config_from_file(fn, system_wide, data);
 	if (do_all && global)
-		git_config_from_file(show_config, global, NULL);
+		git_config_from_file(fn, global, data);
 	if (do_all)
-		git_config_from_file(show_config, local, NULL);
-	git_config_from_parameters(show_config, NULL);
+		git_config_from_file(fn, local, data);
+	git_config_from_parameters(fn, data);
 	if (!do_all && !seen)
-		git_config_from_file(show_config, local, NULL);
+		git_config_from_file(fn, local, data);
 	if (!do_all && !seen && global)
-		git_config_from_file(show_config, global, NULL);
+		git_config_from_file(fn, global, data);
 	if (!do_all && !seen && system_wide)
-		git_config_from_file(show_config, system_wide, NULL);
+		git_config_from_file(fn, system_wide, data);
 
 	free(key);
 	if (regexp) {
@@ -384,6 +398,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			config_exclusive_filename = given_config_file;
 	}
 
+	if (respect_includes == -1)
+		respect_includes = !config_exclusive_filename;
+
 	if (end_null) {
 		term = '\0';
 		delim = '\n';
diff --git a/cache.h b/cache.h
index 10afd71d43..65c1513a40 100644
--- a/cache.h
+++ b/cache.h
@@ -1138,6 +1138,14 @@ extern const char *get_commit_output_encoding(void);
 
 extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
+struct config_include_data {
+	int depth;
+	config_fn_t fn;
+	void *data;
+};
+#define CONFIG_INCLUDE_INIT { 0 }
+extern int git_config_include(const char *name, const char *value, void *data);
+
 extern const char *config_exclusive_filename;
 
 #define MAX_GITNAME (1000)
diff --git a/config.c b/config.c
index 40f9c6d103..e3fcf7553c 100644
--- a/config.c
+++ b/config.c
@@ -28,6 +28,69 @@ static int zlib_compression_seen;
 
 const char *config_exclusive_filename = NULL;
 
+#define MAX_INCLUDE_DEPTH 10
+static const char include_depth_advice[] =
+"exceeded maximum include depth (%d) while including\n"
+"	%s\n"
+"from\n"
+"	%s\n"
+"Do you have circular includes?";
+static int handle_path_include(const char *path, struct config_include_data *inc)
+{
+	int ret = 0;
+	struct strbuf buf = STRBUF_INIT;
+
+	/*
+	 * Use an absolute path as-is, but interpret relative paths
+	 * based on the including config file.
+	 */
+	if (!is_absolute_path(path)) {
+		char *slash;
+
+		if (!cf || !cf->name)
+			return error("relative config includes must come from files");
+
+		slash = find_last_dir_sep(cf->name);
+		if (slash)
+			strbuf_add(&buf, cf->name, slash - cf->name + 1);
+		strbuf_addstr(&buf, path);
+		path = buf.buf;
+	}
+
+	if (!access(path, R_OK)) {
+		if (++inc->depth > MAX_INCLUDE_DEPTH)
+			die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
+			    cf && cf->name ? cf->name : "the command line");
+		ret = git_config_from_file(git_config_include, path, inc);
+		inc->depth--;
+	}
+	strbuf_release(&buf);
+	return ret;
+}
+
+int git_config_include(const char *var, const char *value, void *data)
+{
+	struct config_include_data *inc = data;
+	const char *type;
+	int ret;
+
+	/*
+	 * Pass along all values, including "include" directives; this makes it
+	 * possible to query information on the includes themselves.
+	 */
+	ret = inc->fn(var, value, inc->data);
+	if (ret < 0)
+		return ret;
+
+	type = skip_prefix(var, "include.");
+	if (!type)
+		return ret;
+
+	if (!strcmp(type, "path"))
+		ret = handle_path_include(value, inc);
+	return ret;
+}
+
 static void lowercase(char *p)
 {
 	for (; *p; p++)
@@ -921,9 +984,13 @@ int git_config(config_fn_t fn, void *data)
 {
 	char *repo_config = NULL;
 	int ret;
+	struct config_include_data inc = CONFIG_INCLUDE_INIT;
+
+	inc.fn = fn;
+	inc.data = data;
 
 	repo_config = git_pathdup("config");
-	ret = git_config_early(fn, data, repo_config);
+	ret = git_config_early(git_config_include, &inc, repo_config);
 	if (repo_config)
 		free(repo_config);
 	return ret;
diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh
new file mode 100755
index 0000000000..0a27ec48d0
--- /dev/null
+++ b/t/t1305-config-include.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+
+test_description='test config file include directives'
+. ./test-lib.sh
+
+test_expect_success 'include file by absolute path' '
+	echo "[test]one = 1" >one &&
+	echo "[include]path = \"$PWD/one\"" >.gitconfig &&
+	echo 1 >expect &&
+	git config test.one >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'include file by relative path' '
+	echo "[test]one = 1" >one &&
+	echo "[include]path = one" >.gitconfig &&
+	echo 1 >expect &&
+	git config test.one >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'chained relative paths' '
+	mkdir subdir &&
+	echo "[test]three = 3" >subdir/three &&
+	echo "[include]path = three" >subdir/two &&
+	echo "[include]path = subdir/two" >.gitconfig &&
+	echo 3 >expect &&
+	git config test.three >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'include options can still be examined' '
+	echo "[test]one = 1" >one &&
+	echo "[include]path = one" >.gitconfig &&
+	echo one >expect &&
+	git config include.path >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'listing includes option and expansion' '
+	echo "[test]one = 1" >one &&
+	echo "[include]path = one" >.gitconfig &&
+	cat >expect <<-\EOF &&
+	include.path=one
+	test.one=1
+	EOF
+	git config --list >actual.full &&
+	grep -v ^core actual.full >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'single file lookup does not expand includes by default' '
+	echo "[test]one = 1" >one &&
+	echo "[include]path = one" >.gitconfig &&
+	test_must_fail git config -f .gitconfig test.one &&
+	test_must_fail git config --global test.one &&
+	echo 1 >expect &&
+	git config --includes -f .gitconfig test.one >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'writing config file does not expand includes' '
+	echo "[test]one = 1" >one &&
+	echo "[include]path = one" >.gitconfig &&
+	git config test.two 2 &&
+	echo 2 >expect &&
+	git config --no-includes test.two >actual &&
+	test_cmp expect actual &&
+	test_must_fail git config --no-includes test.one
+'
+
+test_expect_success 'config modification does not affect includes' '
+	echo "[test]one = 1" >one &&
+	echo "[include]path = one" >.gitconfig &&
+	git config test.one 2 &&
+	echo 1 >expect &&
+	git config -f one test.one >actual &&
+	test_cmp expect actual &&
+	cat >expect <<-\EOF &&
+	1
+	2
+	EOF
+	git config --get-all test.one >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'missing include files are ignored' '
+	cat >.gitconfig <<-\EOF &&
+	[include]path = foo
+	[test]value = yes
+	EOF
+	echo yes >expect &&
+	git config test.value >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'absolute includes from command line work' '
+	echo "[test]one = 1" >one &&
+	echo 1 >expect &&
+	git -c include.path="$PWD/one" config test.one >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'relative includes from command line fail' '
+	echo "[test]one = 1" >one &&
+	test_must_fail git -c include.path=one config test.one
+'
+
+test_expect_success 'include cycles are detected' '
+	cat >.gitconfig <<-\EOF &&
+	[test]value = gitconfig
+	[include]path = cycle
+	EOF
+	cat >cycle <<-\EOF &&
+	[test]value = cycle
+	[include]path = .gitconfig
+	EOF
+	cat >expect <<-\EOF &&
+	gitconfig
+	cycle
+	EOF
+	test_must_fail git config --get-all test.value 2>stderr &&
+	grep "exceeded maximum include depth" stderr
+'
+
+test_done

From b4cb824d81d02ab9ab68844661edef027d6e3a4f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 11 Feb 2012 00:58:37 +0100
Subject: [PATCH 2913/3720] Win32: fix deletion of .git/objects sub-directories
 in git-repack

On Windows XP (not Win7), directories cannot be deleted while a find handle
is open, causing "Deletion of directory '...' failed. Should I try again?"
prompts in git-repack and git-gc.

Prior to 19d1e75d "Win32: Unicode file name support (except dirent)",
these failures were silently ignored due to strbuf_free in is_dir_empty
resetting GetLastError to ERROR_SUCCESS.

Close find handles properly before trying to delete directories.

Reported-by: John Chen 
Signed-off-by: Karsten Blees 
---
 builtin/prune-packed.c | 2 +-
 compat/mingw.c         | 7 +++++--
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index f9463deec2..a834417a45 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -36,7 +36,6 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
 		display_progress(progress, i + 1);
 	}
 	pathname[len] = 0;
-	rmdir(pathname);
 }
 
 void prune_packed_objects(int opts)
@@ -65,6 +64,7 @@ void prune_packed_objects(int opts)
 			continue;
 		prune_dir(i, d, pathname, len + 3, opts);
 		closedir(d);
+		rmdir(pathname);
 	}
 	stop_progress(&progress);
 }
diff --git a/compat/mingw.c b/compat/mingw.c
index 183a2a4558..d10734b0eb 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -243,8 +243,11 @@ static int is_dir_empty(const wchar_t *wpath)
 
 	while (!wcscmp(findbuf.cFileName, L".") ||
 			!wcscmp(findbuf.cFileName, L".."))
-		if (!FindNextFileW(handle, &findbuf))
-			return GetLastError() == ERROR_NO_MORE_FILES;
+		if (!FindNextFileW(handle, &findbuf)) {
+			DWORD err = GetLastError();
+			FindClose(handle);
+			return err == ERROR_NO_MORE_FILES;
+		}
 	FindClose(handle);
 	return 0;
 }

From 919fbfd234fb148c51eaad8a95087ed3680cdf57 Mon Sep 17 00:00:00 2001
From: Matthieu Moy 
Date: Sat, 14 Jan 2012 19:55:36 +0100
Subject: [PATCH 2914/3720] bash-completion: don't add quoted space for ZSH
 (fix regression)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit a31e626 (completion: optimize refs completion) introduced a
regression for ZSH users: ref names were completed with a quoted trailing
space (i.e. "git checkout ma" completes to "git checkout master\ "). The
space is convenient for bash users since we use "-o nospace", but a
quoted space is worse than nothing. The absence of trailing space for ZSH
is a long-standing issue, that this patch is not fixing. We just fix the
regression by not appending a space when the shell is ZSH.

Original-patch-by: SZEDER Gábor 
Reported-by: Stefan Haller 
Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 contrib/completion/git-completion.bash | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index d7367e9faa..063fbae96e 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -522,6 +522,13 @@ __gitcomp ()
 __gitcomp_nl ()
 {
 	local IFS=$'\n'
+
+	# ZSH would quote the trailing space added with -S. bash users
+	# will appreciate the extra space to compensate the use of -o nospace.
+	if [ -n "${ZSH_VERSION-}" ] && [ "$suffix" = " " ]; then
+		suffix=""
+	fi
+
 	COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
 }
 

From b8f2e6259f927cd9c6079a2dd3656cd57d759fb5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 2915/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index a0de4e9c6b..c456e7e0ec 100644
--- a/Makefile
+++ b/Makefile
@@ -1193,16 +1193,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 21f28c6118e54cef71be8b980c69963f323446fd Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 2916/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index e55dae1806..4e2309f433 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -167,6 +167,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 94f3eaf603..9c8a72789c 100644
--- a/cache.h
+++ b/cache.h
@@ -605,6 +605,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..cc1b34999d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..699a3dd395 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -113,10 +113,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -318,6 +315,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index e3fcf7553c..4bdb77c35b 100644
--- a/config.c
+++ b/config.c
@@ -749,6 +749,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index c93b8f44df..bf6f0c29ed 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 426ae43be9..cd0169b6af 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -592,4 +592,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 7b84cfdd7c5719b78e92baf606debc73821e64da Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 2917/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index cc1b34999d..665f6abc40 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 4b6f041ac74bdd6d72d84b3e71e0212304d3a726 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 2918/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From f133b6ea6eadecace04223fe05bb832a50aaffe5 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 2919/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 84e1a12f2b7192d782694f426fc9ba74bcdd976b Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 2920/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 376c9fb469a6b5aab7828863f84aeef402a0e577 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 2921/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 64ef3c4013..e2cda370fa 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9499,7 +9499,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 10f5e26dbc540152b21f52b8a90514c518a0bf43 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 2922/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From a1a1bd1a5688ccbb59b6c8b02e6b0a35d3eb7f59 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 2923/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From f5f11fb78cb86dca1b02b129df71d6934080ba5f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 2924/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4e2309f433..2252122ef5 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1720,6 +1720,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index fa7448be5a..b3d631f95d 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -89,7 +91,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -410,6 +417,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -441,6 +486,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -469,6 +521,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b69cf574d7..0cb7346f42 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -979,4 +979,40 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	test_cmp .git/foo .git/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 39fcca4391002304e17a46f1c0b97d8241c7d180 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 2925/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index ef30c557c7..c42fb2a7aa 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 3c7f2729fca5c3aa03128d881314bf6f25113903 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 2926/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index c42fb2a7aa..03292fd832 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 5a9ec6f4a5e0a0225320f3969f0044247a5659f1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 2927/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 09bf778168..9353b6d353 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -169,7 +169,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -377,7 +377,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 665f6abc40..e5f1c36995 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 699a3dd395..ec5c25c36d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -349,3 +349,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index 4bdb77c35b..d05f2898a0 100644
--- a/config.c
+++ b/config.c
@@ -960,7 +960,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index cd0169b6af..44a19ab566 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -596,4 +596,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index 6f2aa699ad..4cb0585cde 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 44beade13dc41c1b4354ee9bfe2abe19d3d14b82 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 2928/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 5783ebf3ab..1489bcff97 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From 36ffe3cbd0dd73b0c43438fa777ac3288c085940 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 2929/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 64d8e2a64d..bb16a7bcb1 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -559,7 +559,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -731,7 +732,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -807,7 +809,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -831,7 +833,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From ee52f46d74e027f6fa04f29d35726b8af9734baa Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 2930/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index e28d5fdebe..102762188a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 1418a6081625f409cd4d57dc0448d508d420618d Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 2931/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 9c8a72789c..ff34ac6be8 100644
--- a/cache.h
+++ b/cache.h
@@ -758,7 +758,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index e5f1c36995..39ce7b446d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index ec5c25c36d..9111ce66e7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -309,6 +309,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 44a19ab566..77a1ff99a1 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 4cb0585cde..242074b1cf 100644
--- a/path.c
+++ b/path.c
@@ -660,10 +660,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 4b39d0d98bd5ca4f80c078a14920b31ec543e0d5 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 2932/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index 9353b6d353..1e0e549e2e 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -377,7 +377,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;

From 58e7b141e1f80204b70d214b058cd1450a882260 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 2933/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 39ce7b446d..71adbc497a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From d9115b7a873415701e1d74023cb7c49f779ced5c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 2934/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From f7966b753490253837bab7c22cdd4b36d6677cde Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 2935/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index e2cda370fa..928a25d904 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -365,7 +365,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9499,18 +9499,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9521,6 +9510,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From f6ccac59cd08190d1f0fc2e4dffd00abff8a811f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 2936/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 71adbc497a..fe3cae3a38 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 53f357e029e1369e2d5800441e29b799b51372ba Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 2937/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9111ce66e7..60e281a7fe 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 6564588e404d81bcf1d60ee85f680b9f56162480 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 2938/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 7a1158f86f483539d88cf656e5dbf1fd82e5566d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 2939/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 342f21f72a0095286f69f02d9869252e99fe787a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 2940/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index cea8756866..9be97ab9ae 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 15fa0b43c7bb838fa32956a242634432c71e4f64 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 2941/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 3fc7380a5e..c5c54800af 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4339,6 +4339,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 99c07dcd03ae6e4af3a132bfa7f72a984fdf1519 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 2942/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index c5c54800af..b762f014b8 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4354,7 +4354,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 42f65d4f7b9ab37b7afb45e5e28b5cff3659edd0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 2943/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 0ffd79cd81..3f3e3e72fd 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -138,6 +139,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 49741a3f2bbbc6cff44a12f8e6517d7b3883a6f9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 2944/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index b3d631f95d..64a499f6e5 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -420,7 +420,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From c1941a72e7dea0b170d2aa05c6f0cfeef6d13e40 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 2945/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index e4ea900783..6e6e1e0268 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -162,6 +163,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -172,6 +189,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->identifier))
+			continue;
+
 		opt->output_priv = w;
 		hit |= grep_source(opt, &w->source);
 		grep_source_clear_data(&w->source);
@@ -418,6 +438,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -884,6 +907,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 182690fe333676d410ef98926f11f8d6467d0664 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 2946/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c456e7e0ec..a79f6eea65 100644
--- a/Makefile
+++ b/Makefile
@@ -308,7 +308,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From 59978713f2251c9ae89a1281f82c9edfd17faeb3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 2947/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index fe3cae3a38..f86800680c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 1d312658b2fea5d2814bed014f2e259ca94191f0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 2948/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index a79f6eea65..f6978d1c71 100644
--- a/Makefile
+++ b/Makefile
@@ -2092,7 +2092,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2132,6 +2132,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From efbae6dc80311100a1b22bfccc398c86736fed98 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 2949/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..18a93cba9f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 7a01406fde5d72fd7f62a8b26c2e2cef7ae1f128 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 2950/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 6e6e1e0268..e1817e45c0 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -975,6 +975,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From e7ac2dd42accd15fed47755fc725a483718469a8 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 2951/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From b2c475d62a1dd3139455b8965fe0b43a827c30b3 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 2952/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f86800680c..61a1230433 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From a71ed3cf8da09a953bc8f7d7364dd226a14bd6d2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 2953/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 613c74bd5421c9fdb8b0d6c5bad77643a2a7540f Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 2954/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 2955/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 9bb2e13e92..c388bf11bf 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -832,12 +832,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 2956/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 63e6e05fd74e57c0b35da51d7736a290e9839f5e Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 2957/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 5d8e4e6c89..d9fc4be050 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 2958/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index f6978d1c71..fa5c59ba5a 100644
--- a/Makefile
+++ b/Makefile
@@ -1187,6 +1187,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1280,6 +1281,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 9f60b5f7332a7765bf81f2a49e729158a60cd224 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 2959/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From fd50266c527300f5fee48056e7cf4128ad8a80e4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 2960/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From c9d0d7c5aa22c8f05d74172f1d2c945b26ca1c78 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 2961/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From e2b3f70bce9f6af234f8f1ed24a19f316f788818 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 2962/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 1d4f37e1ef16b7acdf58d00075cc947a9a8d0dca Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 2963/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 61a1230433..398c11f175 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From bf50209eec9806550469e0c260b788ac4271c6c5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 2964/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 398c11f175..8565118abd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 60e281a7fe..da9c53583a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 2a975bd4f6c3fb4deeeded49e24f250278584301 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 2965/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8565118abd..1b40ff2373 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 248ed19e7a943e6c59dae47fd922093d48ba0c60 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 2966/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index b762f014b8..7c9de73944 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6673,7 +6673,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6721,6 +6733,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 22f2d157e91547e0dfdc972d2ce6633c69ca5992 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 2967/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 7c9de73944..21555d077e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4339,7 +4339,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 3280757f9a35d022ac3b14b27c9e8ddc0fece49a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 2968/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 21555d077e..9f355738a5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6786,7 +6786,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From f65a7cabeaf5f9ac697e933554ed1e9d95fbbc08 Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 2969/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1b40ff2373..952a2a6819 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From f1354f569a338a745af5531802832ccf4cdcf88a Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 2970/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index da9c53583a..1f9f35f63d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 312fa7570d36cb1f82b6ed76240b3cda256d8300 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 2971/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 434c139f07..2ee61f1c91 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -113,7 +114,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -278,7 +284,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From 15b01daac973a3be19b8f4d3d14093066aff260c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 2972/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 2252122ef5..1c95bd864d 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -697,6 +697,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index 2ee61f1c91..3473958acf 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 900a70d24f772808fb85200cbbcb3dcc1ca43db1 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 2973/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1f9f35f63d..407bad231b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 77a1ff99a1..8810d004a4 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From e3df7e7f6a35e8d26fef724981a27a9b7ae12f86 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 2974/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From d1ade3f70d6146fb4ec3f38856ab68c07709cd86 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 2975/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index fa5c59ba5a..2f12f595ef 100644
--- a/Makefile
+++ b/Makefile
@@ -1185,6 +1185,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From 7f96b51959ac3922c9cf51f8a7ecbd8736cb6f2c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 2976/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From 667c49a4ad7ec4fda6e28a3ace0d496b5f1e251c Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 2977/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 2f12f595ef..47baceceff 100644
--- a/Makefile
+++ b/Makefile
@@ -1263,7 +1263,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From 7febb1698dfdf6bc006041a976b3970db0bcf7d1 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 16:50:50 +0000
Subject: [PATCH 2978/3720] gitk: fix the display of files when filtered by
 path

Launching 'gitk -- .' or 'gitk -- ..\t' restricts the display to files
under the given directory but the file list is left empty. This is because
the path_filter function fails to match the filenames which are relative
to the working tree to the filter which is filessytem relative.
This solves the problem by making both names fully qualified filesystem
paths before performing the comparison.

Signed-off-by: Pat Thoyts 
Tested-by: David Aguilar 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 928a25d904..77c38b01b6 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -14,6 +14,26 @@ proc hasworktree {} {
 		  [exec git rev-parse --is-inside-git-dir] == "false"}]
 }
 
+proc gitworktree {} {
+    variable _gitworktree
+    if {[info exists _gitworktree]} {
+	return $_gitworktree
+    }
+    # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+    if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+        # try to set work tree from environment, core.worktree or use
+        # cdup to obtain a relative path to the top of the worktree. If
+        # run from the top, the ./ prefix ensures normalize expands pwd.
+        if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+	    catch {set _gitworktree [exec git config --get core.worktree]}
+	    if {$_gitworktree eq ""} {
+		set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+	    }
+        }
+    }
+    return $_gitworktree
+}
+
 # A simple scheduler for compute-intensive stuff.
 # The aim is to make sure that event handlers for GUI actions can
 # run at least every 50-100 ms.  Unfortunately fileevent handlers are
@@ -7393,19 +7413,15 @@ proc startdiff {ids} {
     }
 }
 
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
 proc path_filter {filter name} {
+    set worktree [gitworktree]
     foreach p $filter {
-	set l [string length $p]
-	if {[string index $p end] eq "/"} {
-	    if {[string compare -length $l $p $name] == 0} {
-		return 1
-	    }
-	} else {
-	    if {[string compare -length $l $p $name] == 0 &&
-		([string length $name] == $l ||
-		 [string index $name $l] eq "/")} {
-		return 1
-	    }
+	set fq_p [file normalize $p]
+	set fq_n [file normalize [file join $worktree $name]]
+	if {[string match [file normalize $fq_p]* $fq_n]} {
+	    return 1
 	}
     }
     return 0

From a1b614819fdd4f18f2995b9906aea8c93ce322c8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 2979/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 47baceceff..63785ee9f6 100644
--- a/Makefile
+++ b/Makefile
@@ -1300,6 +1300,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From ecd474f1f0232fc1b14c0577bdc31a06910766fe Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 2980/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From ce507c9bf01c4382f369a33d5fc0605f47da5f2e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 6 Jan 2012 13:56:09 -0600
Subject: [PATCH 2981/3720] Install Git/I18N.pm even in the absence of Perl's
 MakeMaker

The telltale was that t0202 could not find I18N.pm on msysGit.

Signed-off-by: Johannes Schindelin 
---
 perl/Makefile | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/perl/Makefile b/perl/Makefile
index b2977cd0bc..91848f3d3c 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -24,13 +24,15 @@ ifdef NO_PERL_MAKEMAKER
 instdir_SQ = $(subst ','\'',$(prefix)/lib)
 $(makfile): ../GIT-CFLAGS Makefile
 	echo all: private-Error.pm Git.pm > $@
-	echo '	mkdir -p blib/lib' >> $@
+	echo '	mkdir -p blib/lib/Git' >> $@
+	echo '	$(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@
 	echo '	$(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@
 	echo '	$(RM) blib/lib/Error.pm' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
 	echo '	cp private-Error.pm blib/lib/Error.pm' >> $@
 	echo install: >> $@
-	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)"' >> $@
+	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
+	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm "$$(DESTDIR)$(instdir_SQ)/Git/"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm "$$(DESTDIR)$(instdir_SQ)"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \

From d41dbdcc8e5023192de886d0916cce25a503b44b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 9 Jan 2012 19:16:30 +0100
Subject: [PATCH 2982/3720] Windows/i18n: rename $path to prevent clashes with
 $PATH

Environment variables on Windows are case-insensitive. Rename '$path' in
all calls to eval_gettext to $modulepath so that it is not mistakenly
expanded to the value of the $PATH variable.

[jes: this happens to fix t7406/t7407 on Windows]
[pt: squashed in fix for substitution order error that broke t7400]

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
---
 git-submodule.sh | 52 ++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 05286ff400..8f67e7f5fe 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -105,7 +105,7 @@ module_name()
 	name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
 	test -z "$name" &&
-	die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+	die "$(modulepath=$path eval_gettext "No submodule mapping found in .gitmodules for path '\$modulepath'")"
 	echo "$name"
 }
 
@@ -170,7 +170,7 @@ module_clone()
 		else
 			git-clone $quiet -n "$url" "$path" --separate-git-dir "$gitdir"
 		fi ||
-		die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+		die "$(modulepath=$path eval_gettext "Clone of '\$url' into submodule path '\$modulepath' failed")"
 	fi
 }
 
@@ -261,13 +261,13 @@ cmd_add()
 			s|/*$||
 		')
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
-	die "$(eval_gettext "'\$path' already exists in the index")"
+	die "$(modulepath=$path eval_gettext "'\$modulepath' already exists in the index")"
 
 	if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
 	then
 		cat >&2 </dev/null) &&
 					 test -z "$rev") || git-fetch)) ||
-				die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
+				die "$(modulepath=$path eval_gettext "Unable to fetch in submodule path '\$modulepath'")"
 			fi
 
 			# Is this something we just cloned?
@@ -564,20 +564,20 @@ Maybe you want to use 'update --init'?")"
 			case "$update_module" in
 			rebase)
 				command="git rebase"
-				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to rebase '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': rebased into '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			merge)
 				command="git merge"
-				die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to merge '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': merged in '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			*)
 				command="git checkout $subforce -q"
-				die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to checkout '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': checked out '\$sha1'")"
 				;;
 			esac
 
@@ -599,7 +599,7 @@ Maybe you want to use 'update --init'?")"
 			res=$?
 			if test $res -gt 0
 			then
-				die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+				die_msg="$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 				if test $res -eq 1
 				then
 					err="${err};$die_msg"
@@ -926,7 +926,7 @@ cmd_status()
 				cd "$path" &&
 				eval cmd_status "$orig_args"
 			) ||
-			die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+			die "$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 		fi
 	done
 }

From c675a06b559be7e209fc93f58401ff390928b8d9 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 14:56:49 +0000
Subject: [PATCH 2983/3720] gitk: use a tabbed dialog to edit preferences

This commit converts the user preferences dialog into a tabbed property
sheet grouping general properties, colours and font selections onto
separate pages. The previous implementation was exceeding the screen
height on some systems and this avoids such problems and permits extension
using new pages in the future.

If themed Tk is unavailable or undesired a reasonable facsimile of the
tabbed notebook widget is used instead.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 256 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 160 insertions(+), 96 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 77c38b01b6..dcae0a7547 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10805,6 +10805,139 @@ proc chg_fontparam {v sub op} {
     font config sample -$sub $fontparam($sub)
 }
 
+# Create a property sheet tab page
+proc create_prefs_page {w} {
+    global NS
+    set parent [join [lrange [split $w .] 0 end-1] .]
+    if {[winfo class $parent] eq "TNotebook"} {
+	${NS}::frame $w
+    } else {
+	${NS}::labelframe $w
+    }
+}
+
+proc prefspage_general {notebook} {
+    global NS maxwidth maxgraphpct showneartags showlocalchanges
+    global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
+    global hideremotes want_ttk have_ttk
+
+    set page [create_prefs_page $notebook.general]
+
+    ${NS}::label $page.ldisp -text [mc "Commit list display options"]
+    grid $page.ldisp - -sticky w -pady 10
+    ${NS}::label $page.spacer -text " "
+    ${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"]
+    spinbox $page.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+    grid $page.spacer $page.maxwidthl $page.maxwidth -sticky w
+    ${NS}::label $page.maxpctl -text [mc "Maximum graph width (% of pane)"]
+    spinbox $page.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+    grid x $page.maxpctl $page.maxpct -sticky w
+    ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \
+	-variable showlocalchanges
+    grid x $page.showlocal -sticky w
+    ${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \
+	-variable autoselect
+    spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
+    grid x $page.autoselect $page.autosellen -sticky w
+    ${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \
+	-variable hideremotes
+    grid x $page.hideremotes -sticky w
+
+    ${NS}::label $page.ddisp -text [mc "Diff display options"]
+    grid $page.ddisp - -sticky w -pady 10
+    ${NS}::label $page.tabstopl -text [mc "Tab spacing"]
+    spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
+    grid x $page.tabstopl $page.tabstop -sticky w
+    ${NS}::checkbutton $page.ntag -text [mc "Display nearby tags"] \
+	-variable showneartags
+    grid x $page.ntag -sticky w
+    ${NS}::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \
+	-variable limitdiffs
+    grid x $page.ldiff -sticky w
+    ${NS}::checkbutton $page.lattr -text [mc "Support per-file encodings"] \
+	-variable perfile_attrs
+    grid x $page.lattr -sticky w
+
+    ${NS}::entry $page.extdifft -textvariable extdifftool
+    ${NS}::frame $page.extdifff
+    ${NS}::label $page.extdifff.l -text [mc "External diff tool" ]
+    ${NS}::button $page.extdifff.b -text [mc "Choose..."] -command choose_extdiff
+    pack $page.extdifff.l $page.extdifff.b -side left
+    pack configure $page.extdifff.l -padx 10
+    grid x $page.extdifff $page.extdifft -sticky ew
+
+    ${NS}::label $page.lgen -text [mc "General options"]
+    grid $page.lgen - -sticky w -pady 10
+    ${NS}::checkbutton $page.want_ttk -variable want_ttk \
+	-text [mc "Use themed widgets"]
+    if {$have_ttk} {
+	${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
+    } else {
+	${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
+    }
+    grid x $page.want_ttk $page.ttk_note -sticky w
+    return $page
+}
+
+proc prefspage_colors {notebook} {
+    global NS uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+
+    set page [create_prefs_page $notebook.colors]
+
+    ${NS}::label $page.cdisp -text [mc "Colors: press to choose"]
+    grid $page.cdisp - -sticky w -pady 10
+    label $page.ui -padx 40 -relief sunk -background $uicolor
+    ${NS}::button $page.uibut -text [mc "Interface"] \
+       -command [list choosecolor uicolor {} $page.ui [mc "interface"] setui]
+    grid x $page.uibut $page.ui -sticky w
+    label $page.bg -padx 40 -relief sunk -background $bgcolor
+    ${NS}::button $page.bgbut -text [mc "Background"] \
+	-command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
+    grid x $page.bgbut $page.bg -sticky w
+    label $page.fg -padx 40 -relief sunk -background $fgcolor
+    ${NS}::button $page.fgbut -text [mc "Foreground"] \
+	-command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
+    grid x $page.fgbut $page.fg -sticky w
+    label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
+    ${NS}::button $page.diffoldbut -text [mc "Diff: old lines"] \
+	-command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
+		      [list $ctext tag conf d0 -foreground]]
+    grid x $page.diffoldbut $page.diffold -sticky w
+    label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
+    ${NS}::button $page.diffnewbut -text [mc "Diff: new lines"] \
+	-command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
+		      [list $ctext tag conf dresult -foreground]]
+    grid x $page.diffnewbut $page.diffnew -sticky w
+    label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
+    ${NS}::button $page.hunksepbut -text [mc "Diff: hunk header"] \
+	-command [list choosecolor diffcolors 2 $page.hunksep \
+		      [mc "diff hunk header"] \
+		      [list $ctext tag conf hunksep -foreground]]
+    grid x $page.hunksepbut $page.hunksep -sticky w
+    label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor
+    ${NS}::button $page.markbgbut -text [mc "Marked line bg"] \
+	-command [list choosecolor markbgcolor {} $page.markbgsep \
+		      [mc "marked line background"] \
+		      [list $ctext tag conf omark -background]]
+    grid x $page.markbgbut $page.markbgsep -sticky w
+    label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor
+    ${NS}::button $page.selbgbut -text [mc "Select bg"] \
+	-command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
+    grid x $page.selbgbut $page.selbgsep -sticky w
+    return $page
+}
+
+proc prefspage_fonts {notebook} {
+    global NS
+    set page [create_prefs_page $notebook.fonts]
+    ${NS}::label $page.cfont -text [mc "Fonts: press to choose"]
+    grid $page.cfont - -sticky w -pady 10
+    mkfontdisp mainfont $page [mc "Main font"]
+    mkfontdisp textfont $page [mc "Diff display font"]
+    mkfontdisp uifont $page [mc "User interface font"]
+    return $page
+}
+
 proc doprefs {} {
     global maxwidth maxgraphpct use_ttk NS
     global oldprefs prefstop showneartags showlocalchanges
@@ -10825,106 +10958,37 @@ proc doprefs {} {
     ttk_toplevel $top
     wm title $top [mc "Gitk preferences"]
     make_transient $top .
-    ${NS}::label $top.ldisp -text [mc "Commit list display options"]
-    grid $top.ldisp - -sticky w -pady 10
-    ${NS}::label $top.spacer -text " "
-    ${NS}::label $top.maxwidthl -text [mc "Maximum graph width (lines)"]
-    spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
-    grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
-    ${NS}::label $top.maxpctl -text [mc "Maximum graph width (% of pane)"]
-    spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
-    grid x $top.maxpctl $top.maxpct -sticky w
-    ${NS}::checkbutton $top.showlocal -text [mc "Show local changes"] \
-	-variable showlocalchanges
-    grid x $top.showlocal -sticky w
-    ${NS}::checkbutton $top.autoselect -text [mc "Auto-select SHA1 (length)"] \
-	-variable autoselect
-    spinbox $top.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
-    grid x $top.autoselect $top.autosellen -sticky w
-    ${NS}::checkbutton $top.hideremotes -text [mc "Hide remote refs"] \
-	-variable hideremotes
-    grid x $top.hideremotes -sticky w
 
-    ${NS}::label $top.ddisp -text [mc "Diff display options"]
-    grid $top.ddisp - -sticky w -pady 10
-    ${NS}::label $top.tabstopl -text [mc "Tab spacing"]
-    spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
-    grid x $top.tabstopl $top.tabstop -sticky w
-    ${NS}::checkbutton $top.ntag -text [mc "Display nearby tags"] \
-	-variable showneartags
-    grid x $top.ntag -sticky w
-    ${NS}::checkbutton $top.ldiff -text [mc "Limit diffs to listed paths"] \
-	-variable limitdiffs
-    grid x $top.ldiff -sticky w
-    ${NS}::checkbutton $top.lattr -text [mc "Support per-file encodings"] \
-	-variable perfile_attrs
-    grid x $top.lattr -sticky w
-
-    ${NS}::entry $top.extdifft -textvariable extdifftool
-    ${NS}::frame $top.extdifff
-    ${NS}::label $top.extdifff.l -text [mc "External diff tool" ]
-    ${NS}::button $top.extdifff.b -text [mc "Choose..."] -command choose_extdiff
-    pack $top.extdifff.l $top.extdifff.b -side left
-    pack configure $top.extdifff.l -padx 10
-    grid x $top.extdifff $top.extdifft -sticky ew
-
-    ${NS}::label $top.lgen -text [mc "General options"]
-    grid $top.lgen - -sticky w -pady 10
-    ${NS}::checkbutton $top.want_ttk -variable want_ttk \
-	-text [mc "Use themed widgets"]
-    if {$have_ttk} {
-	${NS}::label $top.ttk_note -text [mc "(change requires restart)"]
+    if {[set use_notebook [expr {$use_ttk && [info command ::ttk::notebook] ne ""}]]} {
+	set notebook [ttk::notebook $top.notebook]
     } else {
-	${NS}::label $top.ttk_note -text [mc "(currently unavailable)"]
+	set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat]
     }
-    grid x $top.want_ttk $top.ttk_note -sticky w
 
-    ${NS}::label $top.cdisp -text [mc "Colors: press to choose"]
-    grid $top.cdisp - -sticky w -pady 10
-    label $top.ui -padx 40 -relief sunk -background $uicolor
-    ${NS}::button $top.uibut -text [mc "Interface"] \
-       -command [list choosecolor uicolor {} $top.ui [mc "interface"] setui]
-    grid x $top.uibut $top.ui -sticky w
-    label $top.bg -padx 40 -relief sunk -background $bgcolor
-    ${NS}::button $top.bgbut -text [mc "Background"] \
-	-command [list choosecolor bgcolor {} $top.bg [mc "background"] setbg]
-    grid x $top.bgbut $top.bg -sticky w
-    label $top.fg -padx 40 -relief sunk -background $fgcolor
-    ${NS}::button $top.fgbut -text [mc "Foreground"] \
-	-command [list choosecolor fgcolor {} $top.fg [mc "foreground"] setfg]
-    grid x $top.fgbut $top.fg -sticky w
-    label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
-    ${NS}::button $top.diffoldbut -text [mc "Diff: old lines"] \
-	-command [list choosecolor diffcolors 0 $top.diffold [mc "diff old lines"] \
-		      [list $ctext tag conf d0 -foreground]]
-    grid x $top.diffoldbut $top.diffold -sticky w
-    label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
-    ${NS}::button $top.diffnewbut -text [mc "Diff: new lines"] \
-	-command [list choosecolor diffcolors 1 $top.diffnew [mc "diff new lines"] \
-		      [list $ctext tag conf dresult -foreground]]
-    grid x $top.diffnewbut $top.diffnew -sticky w
-    label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
-    ${NS}::button $top.hunksepbut -text [mc "Diff: hunk header"] \
-	-command [list choosecolor diffcolors 2 $top.hunksep \
-		      [mc "diff hunk header"] \
-		      [list $ctext tag conf hunksep -foreground]]
-    grid x $top.hunksepbut $top.hunksep -sticky w
-    label $top.markbgsep -padx 40 -relief sunk -background $markbgcolor
-    ${NS}::button $top.markbgbut -text [mc "Marked line bg"] \
-	-command [list choosecolor markbgcolor {} $top.markbgsep \
-		      [mc "marked line background"] \
-		      [list $ctext tag conf omark -background]]
-    grid x $top.markbgbut $top.markbgsep -sticky w
-    label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
-    ${NS}::button $top.selbgbut -text [mc "Select bg"] \
-	-command [list choosecolor selectbgcolor {} $top.selbgsep [mc "background"] setselbg]
-    grid x $top.selbgbut $top.selbgsep -sticky w
+    lappend pages [prefspage_general $notebook] [mc "General"]
+    lappend pages [prefspage_colors $notebook] [mc "Colors"]
+    lappend pages [prefspage_fonts $notebook] [mc "Fonts"]
+    foreach {page title} $pages {
+	if {$use_notebook} {
+	    $notebook add $page -text $title
+	} else {
+	    set btn [${NS}::button $notebook.b_[string map {. X} $page] \
+			 -text $title -command [list raise $page]]
+	    $page configure -text $title
+	    grid $btn -row 0 -column [incr col] -sticky w
+	    grid $page -row 1 -column 0 -sticky news -columnspan 100
+	}
+    }
 
-    ${NS}::label $top.cfont -text [mc "Fonts: press to choose"]
-    grid $top.cfont - -sticky w -pady 10
-    mkfontdisp mainfont $top [mc "Main font"]
-    mkfontdisp textfont $top [mc "Diff display font"]
-    mkfontdisp uifont $top [mc "User interface font"]
+    if {!$use_notebook} {
+	grid columnconfigure $notebook 0 -weight 1
+	grid rowconfigure $notebook 1 -weight 1
+	raise [lindex $pages 0]
+    }
+
+    grid $notebook -sticky news -padx 2 -pady 2
+    grid rowconfigure $top 0 -weight 1
+    grid columnconfigure $top 0 -weight 1
 
     ${NS}::frame $top.buts
     ${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active
@@ -10936,7 +11000,7 @@ proc doprefs {} {
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
     grid $top.buts - - -pady 10 -sticky ew
     grid columnconfigure $top 2 -weight 1
-    bind $top  "focus $top.buts.ok"
+    bind $top  [list focus $top.buts.ok]
 }
 
 proc choose_extdiff {} {

From 8b5d6ccfe061635a6550a9112acb1c25ab96a790 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Mon, 30 Jan 2012 23:38:42 +0000
Subject: [PATCH 2984/3720] gitk: fix setting font display with new tabbed
 dialog layout.

The changes to the dialog window tree broke the preview of the selected
font on the button. This corrects that issue.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index dcae0a7547..a62f25d549 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10751,7 +10751,7 @@ proc fontok {} {
     if {$fontparam(slant) eq "italic"} {
 	lappend fontpref($f) "italic"
     }
-    set w $prefstop.$f
+    set w $prefstop.notebook.fonts.$f
     $w conf -text $fontparam(family) -font $fontpref($f)
 
     fontcan

From beb997b41a74c44f7789deb111a6718e93edf89d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 3 Feb 2012 00:12:04 -0600
Subject: [PATCH 2985/3720] Teach 'git remote' that the config var
 branch.*.rebase can be 'interactive'

Signed-off-by: Johannes Schindelin 
---
 builtin/remote.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index f54a89adc7..025a8a2ca1 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -253,7 +253,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	int rebase;
+	enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
 };
 
 static struct string_list branch_list;
@@ -310,7 +310,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			}
 			string_list_append(&info->merge, xstrdup(value));
 		} else
-			info->rebase = git_config_bool(orig_key, value);
+			info->rebase = value && *value == 'i' ?
+				INTERACTIVE_REBASE :
+				(git_config_bool(orig_key, value) ?
+				 NORMAL_REBASE : NO_REBASE);
 	}
 	return 0;
 }
@@ -994,7 +997,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf("rebases onto remote %s\n", merge->items[0].string);
+		printf("rebases %sonto remote %s\n",
+			branch_info->rebase == INTERACTIVE_REBASE ?
+			"interactively " : "", merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf(" merges with remote %s\n", merge->items[0].string);

From fba7c6f7ea2361eda7c889d8c48f3326125e20c6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:28:37 +0100
Subject: [PATCH 2986/3720] git-gui: fix encoding in git-gui file browser

Assume git tree objects (i.e. output of git-ls-tree) are encoded in system
encoding, for display in the git-gui file browser.

Signed-off-by: Karsten Blees 
---
 git-gui/lib/browser.tcl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 0328338fda..4fca8fb13c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary -encoding binary
+	fconfigure $fd -blocking 0 -translation binary
 	fileevent $fd readable [cb _read $fd]
 }
 

From 7797bf5ed462440046af4864c0684f5a93be626a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:38:07 +0100
Subject: [PATCH 2987/3720] gitk: fix file name encoding in diff hunk headers

Decode file names from system encoding in all diff hunk header lines, not
just the first (i.e. print nice file names in 'rename from' / 'rename to' /
'Binary files' lines, too).

Signed-off-by: Karsten Blees 
---
 gitk-git/gitk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index a62f25d549..3660096db5 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7811,6 +7811,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
+	    set line [encoding convertfrom $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {

From 3c4baa893769a593acd1dc44a5f878c17376f992 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 19:06:41 +0100
Subject: [PATCH 2988/3720] Revert "Windows: teach getenv to do a
 case-sensitive search"

This reverts commit df599e9612788b728ce43a03159b85f1fe624d6a.

As of 5e9637c6 "i18n: add infrastructure for translating Git with gettext",
eval_gettext uses MinGW envsubst.exe instead of git-sh-i18n--envsubst.exe
for variable substitution. This breaks git-submodule.sh messages and tests,
as envsubst.exe doesn't support case-sensitive environment lookup (the same
is true for almost everything on Windows, including MSys and Cygwin tools).

30a615ac "Windows/i18n: rename $path to prevent clashes with $PATH" renames
the conflicting variable in git-submodule.sh, so that it works on Windows
(i.e. with case-insensitive environment, regardless of the toolset).

Revert to the documented behaviour of case-insensitive environment on
Windows.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 952a2a6819..1135b4bb78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1182,31 +1182,14 @@ char **make_augmented_environ(const char *const *vars)
 }
 
 #undef getenv
-
-/*
- * The system's getenv looks up the name in a case-insensitive manner.
- * This version tries a case-sensitive lookup and falls back to
- * case-insensitive if nothing was found.  This is necessary because,
- * as a prominent example, CMD sets 'Path', but not 'PATH'.
- * Warning: not thread-safe.
- */
-static char *getenv_cs(const char *name)
-{
-	size_t len = strlen(name);
-	int i = lookup_env(environ, name, len);
-	if (i >= 0)
-		return environ[i] + len + 1;	/* skip past name and '=' */
-	return getenv(name);
-}
-
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv_cs(name);
+	char *result = getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv_cs("TMP");
+		result = getenv("TMP");
 		if (!result)
-			result = getenv_cs("TEMP");
+			result = getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */

From 4030c7de7f3685ee3358e0a99fb029998fe4f682 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:19:31 +0100
Subject: [PATCH 2989/3720] Revert "mingw.c: move definition of mingw_getenv
 down"

This reverts commit 06bc4b796ad69ba93f0a8c451368602e0553c2d3.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1135b4bb78..649c6857dd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -180,7 +180,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	vsnprintf(question, sizeof(question), format, args);
 	va_end(args);
 
-	if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
+	if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
 		retry_hook[1] = question;
 		return !run_command_v_opt(retry_hook, 0);
 	}
@@ -665,6 +665,23 @@ char *mingw_getcwd(char *pointer, int len)
 	return ret;
 }
 
+#undef getenv
+char *mingw_getenv(const char *name)
+{
+	char *result = getenv(name);
+	if (!result && !strcmp(name, "TMPDIR")) {
+		/* on Windows it is TMP and TEMP */
+		result = getenv("TMP");
+		if (!result)
+			result = getenv("TEMP");
+	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
+	return result;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -764,7 +781,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-	char *p, **path, *envpath = mingw_getenv("PATH");
+	char *p, **path, *envpath = getenv("PATH");
 	int i, n = 0;
 
 	if (!envpath || !*envpath)
@@ -1181,23 +1198,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-	char *result = getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
-		if (!result)
-			result = getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 47f10dd0541c6c0e6ddd6bdf06510e220f2b19b3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:24:19 +0100
Subject: [PATCH 2990/3720] Win32: Thread-safe windows console output

Winansi.c has many static variables that are accessed and modified from
the [v][f]printf / fputs functions overridden in the file. This may cause
multi threaded git commands that print to the console to produce corrupted
output or even crash.

Additionally, winansi.c doesn't override all functions that can be used to
print to the console (e.g. fwrite, write, fputc are missing), so that ANSI
escapes don't work properly for some git commands (e.g. git-grep).

Instead of doing ANSI emulation in just a few wrapped functions on top of
the IO API, let's plug into the IO system and take advantage of the thread
safety inherent to the IO system.

Redirect stdout and stderr to a pipe if they point to the console. A
background thread reads from the pipe, handles ANSI escape sequences and
UTF-8 to UTF-16 conversion, then writes to the console.

The pipe-based stdout and stderr replacements must be set to unbuffered, as
MSVCRT doesn't support line buffering and fully buffered streams are
inappropriate for console output.

Due to the byte-oriented pipe, ANSI escape sequences and multi-byte UTF-8
sequences can no longer be expected to arrive in one piece. Replace the
string-based ansi_emulate() with a simple stateful parser (this also fixes
colored diff hunk headers, which were broken as of commit 2efcc977).

Override isatty to return true for the pipes redirecting to the console.

Exec/spawn obtain the original console handle to pass to the next process
via winansi_get_osfhandle().

All other overrides are gone, the default stdio implementations work as
expected with the piped stdout/stderr descriptors.

Global variables are either initialized on startup (single threaded) or
exclusively modified by the background thread. Threads communicate through
the pipe, no further synchronization is necessary.

The background thread is terminated by disonnecting the pipe after flushing
the stdio and pipe buffers. This doesn't work for anonymous pipes (created
via CreatePipe), as DisconnectNamedPipe only works on the read end, which
discards remaining data. Thus we have to setup the pipe manually, with the
write end beeing the server (opened with CreateNamedPipe) and the read end
the client (opened with CreateFile).

Limitations: doesn't track reopened or duped file descriptors, i.e.:
- fdopen(1/2) returns fully buffered streams
- dup(1/2), dup2(1/2) returns normal pipe descriptors (i.e. isatty() =
  false, winansi_get_osfhandle won't return the original console handle)

Currently, only the git-format-patch command uses xfdopen(xdup(1)) (see
"realstdout" in builtin/log.c), but works well with these limitations.

Many thanks to Atsushi Nakagawa  for suggesting and
reviewing the thread-exit-mechanism.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c   |   9 +-
 compat/mingw.h   |  12 +-
 compat/winansi.c | 420 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 282 insertions(+), 159 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 649c6857dd..190e7b7681 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -917,9 +917,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	memset(&si, 0, sizeof(si));
 	si.cb = sizeof(si);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-	si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-	si.hStdError = (HANDLE) _get_osfhandle(fherr);
+	si.hStdInput = winansi_get_osfhandle(fhin);
+	si.hStdOutput = winansi_get_osfhandle(fhout);
+	si.hStdError = winansi_get_osfhandle(fherr);
 
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
@@ -1878,4 +1878,7 @@ void mingw_startup()
 	_setmode(_fileno(stdin), _O_BINARY);
 	_setmode(_fileno(stdout), _O_BINARY);
 	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
 }
diff --git a/compat/mingw.h b/compat/mingw.h
index 407bad231b..2683adcaf7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -288,14 +288,10 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-int winansi_vfprintf(FILE *stream, const char *format, va_list list);
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
-#define vfprintf winansi_vfprintf
+void winansi_init(void);
+int winansi_isatty(int fd);
+HANDLE winansi_get_osfhandle(int fd);
+#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index bec6713b74..a3e4d88295 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,18 +4,13 @@
 
 #undef NOGDI
 #include "../git-compat-util.h"
-#include 
 #include 
 #include 
 
 /*
  Functions to be wrapped:
 */
-#undef printf
-#undef fprintf
-#undef fputs
-#undef vfprintf
-/* TODO: write */
+#undef isatty
 
 /*
  ANSI codes used by git: m, K
@@ -28,7 +23,10 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
-static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hwrite1 = INVALID_HANDLE_VALUE, hwrite2 = INVALID_HANDLE_VALUE;
+static HANDLE hconsole1, hconsole2;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -44,27 +42,19 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void print_font_warning(void)
+static void warn_if_raster_font(void)
 {
-	warning("Your console font probably doesn\'t support Unicode. If "
-		"you experience strange characters in the output, consider "
-		"switching to a TrueType font such as Lucida Console!");
-}
-
-static void check_truetype_font(void)
-{
-	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't do this twice */
-	if (truetype_font_checked)
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
 		return;
-	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
+			GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);
@@ -73,8 +63,8 @@ static void check_truetype_font(void)
 	} else {
 		/* pre-Vista: check default console font in registry */
 		HKEY hkey;
-		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
-				KEY_READ, &hkey)) {
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+				0, KEY_READ, &hkey)) {
 			DWORD size = sizeof(fontFamily);
 			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
 					(LPVOID) &fontFamily, &size);
@@ -82,61 +72,63 @@ static void check_truetype_font(void)
 		}
 	}
 
-	if (!(fontFamily & TMPF_TRUETYPE))
-		atexit(print_font_warning);
+	if (!(fontFamily & TMPF_TRUETYPE)) {
+		const wchar_t *msg = L"\nWarning: Your console font probably "
+			L"doesn\'t support Unicode. If you experience strange "
+			L"characters in the output, consider switching to a "
+			L"TrueType font such as Lucida Console!\n";
+		WriteConsoleW(console, msg, wcslen(msg), NULL, NULL);
+	}
 }
 
-static int is_console(FILE *stream)
+static int is_console(int fd)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
 	HANDLE hcon;
 
 	static int initialized = 0;
 
-	/* use cached value if stream hasn't changed */
-	if (stream == last_stream)
-		return console != NULL;
-
-	last_stream = stream;
-	console = NULL;
-
-	/* get OS handle of the stream */
-	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	/* get OS handle of the file descriptor */
+	hcon = (HANDLE) _get_osfhandle(fd);
 	if (hcon == INVALID_HANDLE_VALUE)
 		return 0;
 
+	/* check if its a device (i.e. console, printer, serial port) */
+	if (GetFileType(hcon) != FILE_TYPE_CHAR)
+		return 0;
+
 	/* check if its a handle to a console output screen buffer */
 	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
+	/* initialize attributes */
 	if (!initialized) {
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
 	}
 
-	console = hcon;
 	return 1;
 }
 
-static int write_console(const char *str, size_t len)
-{
-	/* convert utf-8 to utf-16, write directly to console */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
-	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
-	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
 
+static void write_console(unsigned char *str, size_t len)
+{
+	/* only called from console_thread, so a static buffer will do */
+	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+
+	/* convert utf-8 to utf-16 */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
+			ARRAY_SIZE(wbuf));
+
+	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/*
-	 * if non-ascii characters are printed, check that the current console
-	 * font supports this
-	 */
+	/* remember if non-ascii characters are printed */
 	if (wlen != len)
-		check_truetype_font();
-
-	/* return original (utf-8 encoded) length */
-	return len;
+		non_ascii_used = 1;
 }
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
@@ -182,18 +174,13 @@ static void erase_in_line(void)
 		&dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-	const char *func;
-	size_t len = strspn(str, "0123456789;");
-	func = str + len;
-
-	switch (*func) {
+	int i;
+	switch (func) {
 	case 'm':
-		do {
-			long val = strtol(str, (char **)&str, 10);
-			switch (val) {
+		for (i = 0; i < paramlen; i++) {
+			switch (params[i]) {
 			case 0: /* reset */
 				attr = plain_attr;
 				negative = 0;
@@ -316,9 +303,7 @@ static const char *set_attr(const char *str)
 				/* Unsupported code */
 				break;
 			}
-			str++;
-		} while (*(str-1) == ';');
-
+		}
 		set_console_attr();
 		break;
 	case 'K':
@@ -328,112 +313,251 @@ static const char *set_attr(const char *str)
 		/* Unsupported code */
 		break;
 	}
-
-	return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+	TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-	int rv = 0;
-	const char *pos = str;
+	unsigned char buffer[BUFFER_SIZE];
+	DWORD bytes;
+	int start, end = 0, c, parampos = 0, state = TEXT;
+	int params[MAX_PARAMS];
 
-	fflush(stream);
+	while (1) {
+		/* read next chunk of bytes from the pipe */
+		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+				NULL)) {
+			/* exit if pipe has been closed or disconnected */
+			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+					GetLastError() == ERROR_BROKEN_PIPE)
+				break;
+			/* ignore other errors */
+			continue;
+		}
 
-	while (*pos) {
-		pos = strstr(str, "\033[");
-		if (pos) {
-			size_t len = pos - str;
+		/* scan the bytes and handle ANSI control codes */
+		bytes += end;
+		start = end = 0;
+		while (end < bytes) {
+			c = buffer[end++];
+			switch (state) {
+			case TEXT:
+				if (c == ESCAPE) {
+					/* print text seen so far */
+					if (end - 1 > start)
+						write_console(buffer + start,
+							end - 1 - start);
 
-			if (len) {
-				size_t out_len = write_console(str, len);
-				rv += out_len;
-				if (out_len < len)
-					return rv;
+					/* then start parsing escape sequence */
+					start = end - 1;
+					memset(params, 0, sizeof(params));
+					parampos = 0;
+					state = ESCAPE;
+				}
+				break;
+
+			case ESCAPE:
+				/* continue if "\033[", otherwise bail out */
+				state = (c == BRACKET) ? BRACKET : TEXT;
+				break;
+
+			case BRACKET:
+				/* parse [0-9;]* into array of parameters */
+				if (c >= '0' && c <= '9') {
+					params[parampos] *= 10;
+					params[parampos] += c - '0';
+				} else if (c == ';') {
+					/*
+					 * next parameter, bail out if out of
+					 * bounds
+					 */
+					parampos++;
+					if (parampos >= MAX_PARAMS)
+						state = TEXT;
+				} else {
+					/*
+					 * end of escape sequence, change
+					 * console attributes
+					 */
+					set_attr(c, params, parampos + 1);
+					start = end;
+					state = TEXT;
+				}
+				break;
+			}
+		}
+
+		/* print remaining text unless parsing an escape sequence */
+		if (state == TEXT && end > start) {
+			/* check for incomplete UTF-8 sequences and fix end */
+			if (buffer[end - 1] >= 0x80) {
+				if (buffer[end -1] >= 0xc0)
+					end--;
+				else if (end - 1 > start &&
+						buffer[end - 2] >= 0xe0)
+					end -= 2;
+				else if (end - 2 > start &&
+						buffer[end - 3] >= 0xf0)
+					end -= 3;
 			}
 
-			str = pos + 2;
-			rv += 2;
+			/* print remaining complete UTF-8 sequences */
+			if (end > start)
+				write_console(buffer + start, end - start);
 
-			pos = set_attr(str);
-			rv += pos - str;
-			str = pos;
+			/* move remaining bytes to the front */
+			if (end < bytes)
+				memmove(buffer, buffer + end, bytes - end);
+			end = bytes - end;
 		} else {
-			size_t len = strlen(str);
-			rv += write_console(str, len);
-			return rv;
+			/* all data has been consumed, mark buffer empty */
+			end = 0;
 		}
 	}
-	return rv;
+
+	/* check if the console font supports unicode */
+	warn_if_raster_font();
+
+	CloseHandle(hread);
+	return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-	int rv;
+	/* flush all streams */
+	_flushall();
 
-	if (!is_console(stream))
-		return fputs(str, stream);
+	/* signal console thread to exit */
+	FlushFileBuffers(hwrite);
+	DisconnectNamedPipe(hwrite);
 
-	rv = ansi_emulate(str, stream);
+	/* wait for console thread to copy remaining data */
+	WaitForSingleObject(hthread, INFINITE);
 
-	if (rv >= 0)
-		return 0;
+	/* cleanup handles... */
+	if (hwrite1 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite1);
+	if (hwrite2 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite2);
+	CloseHandle(hwrite);
+	CloseHandle(hthread);
+}
+
+static void die_lasterr(const char *fmt, ...)
+{
+	va_list params;
+	va_start(params, fmt);
+	errno = err_win_to_posix(GetLastError());
+	die_errno(fmt, params);
+	va_end(params);
+}
+
+static HANDLE duplicate_handle(HANDLE hnd)
+{
+	HANDLE hresult, hproc = GetCurrentProcess();
+	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+			DUPLICATE_SAME_ACCESS))
+		die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+	return hresult;
+}
+
+static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+{
+	/* get original console handle */
+	int fd = _fileno(stream);
+	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
+	if (hcon == INVALID_HANDLE_VALUE)
+		die_errno("_get_osfhandle(%i) failed", fd);
+
+	/* save a copy to phcon and console (used by the background thread) */
+	console = *phcon = duplicate_handle(hcon);
+
+	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
+	if (_dup2(new_fd, fd))
+		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+
+	/* no buffering, or stdout / stderr will be out of sync */
+	setbuf(stream, NULL);
+	return (HANDLE) _get_osfhandle(fd);
+}
+
+void winansi_init(void)
+{
+	int con1, con2, hwrite_fd;
+	char name[32];
+
+	/* check if either stdout or stderr is a console output screen buffer */
+	con1 = is_console(1);
+	con2 = is_console(2);
+	if (!con1 && !con2)
+		return;
+
+	/* create a named pipe to communicate with the console thread */
+	sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+	hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+	if (hwrite == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateNamedPipe failed");
+
+	hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (hread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateFile for named pipe failed");
+
+	/* start console spool thread on the pipe's read end */
+	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+	if (hthread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateThread(console_thread) failed");
+
+	/* schedule cleanup routine */
+	if (atexit(winansi_exit))
+		die_errno("atexit(winansi_exit) failed");
+
+	/* create a file descriptor for the write end of the pipe */
+	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
+	if (hwrite_fd == -1)
+		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
+
+	/* redirect stdout / stderr to the pipe */
+	if (con1)
+		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+	if (con2)
+		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
+
+	/* close pipe file descriptor (also closes the duped hwrite) */
+	close(hwrite_fd);
+}
+
+static int is_same_handle(HANDLE hnd, int fd)
+{
+	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
+}
+
+/*
+ * Return true if stdout / stderr is a pipe redirecting to the console.
+ */
+int winansi_isatty(int fd)
+{
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return 1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return 1;
 	else
-		return EOF;
+		return isatty(fd);
 }
 
-int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-	int len, rv;
-	char small_buf[256];
-	char *buf = small_buf;
-	va_list cp;
-
-	if (!is_console(stream))
-		goto abort;
-
-	va_copy(cp, list);
-	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-	va_end(cp);
-
-	if (len > sizeof(small_buf) - 1) {
-		buf = malloc(len + 1);
-		if (!buf)
-			goto abort;
-
-		len = vsnprintf(buf, len + 1, format, list);
-	}
-
-	rv = ansi_emulate(buf, stream);
-
-	if (buf != small_buf)
-		free(buf);
-	return rv;
-
-abort:
-	rv = vfprintf(stream, format, list);
-	return rv;
-}
-
-int winansi_fprintf(FILE *stream, const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stream, format, list);
-	va_end(list);
-
-	return rv;
-}
-
-int winansi_printf(const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stdout, format, list);
-	va_end(list);
-
-	return rv;
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return hconsole1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return hconsole2;
+	else
+		return (HANDLE) _get_osfhandle(fd);
 }

From aba58de5f0de693770d2fef1ced9167085644675 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:05:06 +0100
Subject: [PATCH 2991/3720] Win32: add Unicode conversion functions

Add Unicode conversion functions to convert between Windows native UTF-16LE
encoding to UTF-8 and back.

To support repositories with legacy-encoded file names, the UTF-8 to UTF-16
conversion function tries to create valid, unique file names even for
invalid UTF-8 byte sequences, so that these repositories can be checked out
without error.

The current implementation leaves invalid UTF-8 bytes in range 0xa0 - 0xff
as is (producing printable Unicode chars \u00a0 - \u00ff, equivalent to
ISO-8859-1), and converts 0x80 - 0x9f to hex-code (\u0080 - \u009f are
control chars).

The Windows MultiByteToWideChar API was not used as it either drops invalid
UTF-8 sequences (on Win2k/XP; producing non-unique or even empty file
names) or converts them to the replacement char \ufffd (Vista/7; causing
ERROR_INVALID_NAME in subsequent calls to file system APIs).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c |  85 ++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 190e7b7681..8ed43f9bf1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1859,6 +1859,91 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
diff --git a/compat/mingw.h b/compat/mingw.h
index 2683adcaf7..ddb228473b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -326,6 +326,110 @@ void mingw_mark_as_git_dir(const char *dir);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A replacement of main() that adds win32 specific initialization.
  */

From 004b1b24811c3397b4c4eddb18fb9f982b93c16b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 21:28:22 +0100
Subject: [PATCH 2992/3720] Win32: Unicode file name support (except dirent)

Replaces Windows "ANSI" APIs dealing with file- or path names with their
Unicode equivalent, adding UTF-8/UTF-16LE conversion as necessary.

The dirent API (opendir/readdir/closedir) is updated in a separate commit.

Adds trivial wrappers for access, chmod and chdir.

Adds wrapper for mktemp (needed for both mkstemp and mkdtemp).

The simplest way to convert a repository with legacy-encoded (e.g. Cp1252)
file names to UTF-8 ist to checkout with an old msysgit version and
"git add --all & git commit" with the new version.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 210 ++++++++++++++++++++++++++++++++++---------------
 compat/mingw.h |  13 +++
 2 files changed, 158 insertions(+), 65 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8ed43f9bf1..5d5f30bd2c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "win32.h"
 #include 
+#include 
 #include "../strbuf.h"
 #include "../run-command.h"
 #include "../cache.h"
@@ -200,14 +201,16 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	}
 }
 
-#undef unlink
 int mingw_unlink(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
 	/* read-only files cannot be removed */
-	chmod(pathname, 0666);
-	while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
 		/*
@@ -223,43 +226,40 @@ int mingw_unlink(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = unlink(pathname);
+	       ret = _wunlink(wpathname);
 	return ret;
 }
 
-static int is_dir_empty(const char *path)
+static int is_dir_empty(const wchar_t *wpath)
 {
-	struct strbuf buf = STRBUF_INIT;
-	WIN32_FIND_DATAA findbuf;
+	WIN32_FIND_DATAW findbuf;
 	HANDLE handle;
-
-	strbuf_addf(&buf, "%s\\*", path);
-	handle = FindFirstFileA(buf.buf, &findbuf);
-	if (handle == INVALID_HANDLE_VALUE) {
-		strbuf_release(&buf);
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
 		return GetLastError() == ERROR_NO_MORE_FILES;
-	}
 
-	while (!strcmp(findbuf.cFileName, ".") ||
-			!strcmp(findbuf.cFileName, ".."))
-		if (!FindNextFile(handle, &findbuf)) {
-			strbuf_release(&buf);
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf))
 			return GetLastError() == ERROR_NO_MORE_FILES;
-		}
 	FindClose(handle);
-	strbuf_release(&buf);
 	return 0;
 }
 
-#undef rmdir
 int mingw_rmdir(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
-	while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
-		if (!is_dir_empty(pathname)) {
+		if (!is_dir_empty(wpathname)) {
 			errno = ENOTEMPTY;
 			break;
 		}
@@ -276,14 +276,14 @@ int mingw_rmdir(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = rmdir(pathname);
+	       ret = _wrmdir(wpathname);
 	return ret;
 }
 
-static int make_hidden(const char *path)
+static int make_hidden(const wchar_t *path)
 {
-	DWORD attribs = GetFileAttributes(path);
-	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+	DWORD attribs = GetFileAttributesW(path);
+	if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
 		return 0;
 	errno = err_win_to_posix(GetLastError());
 	return -1;
@@ -291,19 +291,23 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
-	    make_hidden(dir))
-		warning("Failed to make '%s' hidden", dir);
+	wchar_t wdir[MAX_PATH];
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
+		if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
+			warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
 		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
 		 "dotGitOnly" : "true"));
 }
 
-#undef mkdir
 int mingw_mkdir(const char *path, int mode)
 {
-	int ret = mkdir(path);
+	int ret;
+	wchar_t wpath[MAX_PATH];
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
 	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
 		/*
 		 * In Windows a file or dir starting with a dot is not
@@ -312,17 +316,17 @@ int mingw_mkdir(const char *path, int mode)
 		 */
 		const char *start = basename((char*)path);
 		if (*start == '.')
-			return make_hidden(path);
+			return make_hidden(wpath);
 	}
 	return ret;
 }
 
-#undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
 	va_list args;
 	unsigned mode;
 	int fd;
+	wchar_t wfilename[MAX_PATH];
 
 	va_start(args, oflags);
 	mode = va_arg(args, int);
@@ -331,10 +335,12 @@ int mingw_open (const char *filename, int oflags, ...)
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
 
-	fd = open(filename, oflags, mode);
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	fd = _wopen(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
-		DWORD attrs = GetFileAttributes(filename);
+		DWORD attrs = GetFileAttributesW(wfilename);
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
@@ -346,7 +352,7 @@ int mingw_open (const char *filename, int oflags, ...)
 		 * such a file is created.
 		 */
 		const char *start = basename((char*)filename);
-		if (*start == '.' && make_hidden(filename))
+		if (*start == '.' && make_hidden(wfilename))
 			warning("Could not mark '%s' as hidden.", filename);
 	}
 	return fd;
@@ -369,38 +375,69 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 	return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
-#undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = fopen(filename, otype);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfopen(wfilename, wotype);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
-#undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = freopen(filename, otype, stream);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -426,10 +463,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
  */
 static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
-	int err;
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
-	if (!(err = get_file_attr(file_name, &fdata))) {
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
 		buf->st_ino = 0;
 		buf->st_gid = 0;
 		buf->st_uid = 0;
@@ -442,8 +481,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-			WIN32_FIND_DATAA findbuf;
-			HANDLE handle = FindFirstFileA(file_name, &findbuf);
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
 			if (handle != INVALID_HANDLE_VALUE) {
 				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
 						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
@@ -462,7 +501,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		}
 		return 0;
 	}
-	errno = err;
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	default:
+		errno = ENOENT;
+		break;
+	}
 	return -1;
 }
 
@@ -551,16 +606,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
 {
 	FILETIME mft, aft;
 	int fh, rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
 	/* must have write permission */
-	DWORD attrs = GetFileAttributes(file_name);
+	attrs = GetFileAttributesW(wfilename);
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors here; open() will report them */
-		SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
 	}
 
-	if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+	if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
 		rc = -1;
 		goto revert_attrs;
 	}
@@ -583,7 +642,7 @@ revert_attrs:
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors again */
-		SetFileAttributes(file_name, attrs);
+		SetFileAttributesW(wfilename, attrs);
 	}
 	return rc;
 }
@@ -594,6 +653,18 @@ unsigned int sleep (unsigned int seconds)
 	return 0;
 }
 
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
 int mkstemp(char *template)
 {
 	char *filename = mktemp(template);
@@ -652,17 +723,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
 	return result;
 }
 
-#undef getcwd
 char *mingw_getcwd(char *pointer, int len)
 {
 	int i;
-	char *ret = getcwd(pointer, len);
-	if (!ret)
-		return ret;
+	wchar_t wpointer[MAX_PATH];
+	if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+		return NULL;
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
 	for (i = 0; pointer[i]; i++)
 		if (pointer[i] == '\\')
 			pointer[i] = '/';
-	return ret;
+	return pointer;
 }
 
 #undef getenv
@@ -1495,33 +1567,36 @@ int mingw_rename(const char *pold, const char *pnew)
 {
 	DWORD attrs, gle;
 	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+		return -1;
 
 	/*
 	 * Try native rename() first to get errno right.
 	 * It is based on MoveFile(), which cannot overwrite existing files.
 	 */
-	if (!rename(pold, pnew))
+	if (!_wrename(wpold, wpnew))
 		return 0;
 	if (errno != EEXIST)
 		return -1;
 repeat:
-	if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 		return 0;
 	/* TODO: translate more errors */
 	gle = GetLastError();
 	if (gle == ERROR_ACCESS_DENIED &&
-	    (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
 		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
 			errno = EISDIR;
 			return -1;
 		}
 		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
-		    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
-			if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 				return 0;
 			gle = GetLastError();
 			/* revert file attributes on failure */
-			SetFileAttributes(pnew, attrs);
+			SetFileAttributesW(wpnew, attrs);
 		}
 	}
 	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
@@ -1731,11 +1806,16 @@ void mingw_open_html(const char *unixpath)
 
 int link(const char *oldpath, const char *newpath)
 {
-	typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+	typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
 	static T create_hard_link = NULL;
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
 	if (!create_hard_link) {
 		create_hard_link = (T) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+			GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
 		if (!create_hard_link)
 			create_hard_link = (T)-1;
 	}
@@ -1743,7 +1823,7 @@ int link(const char *oldpath, const char *newpath)
 		errno = ENOSYS;
 		return -1;
 	}
-	if (!create_hard_link(newpath, oldpath, NULL)) {
+	if (!create_hard_link(wnewpath, woldpath, NULL)) {
 		errno = err_win_to_posix(GetLastError());
 		return -1;
 	}
diff --git a/compat/mingw.h b/compat/mingw.h
index ddb228473b..ea8c1f8993 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -182,6 +182,19 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 

From c4241631507d198eb0ef828584adcb758111dd9c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:01:09 +0100
Subject: [PATCH 2993/3720] Win32: Unicode file name support (dirent)

Changes opendir/readdir to use Windows Unicode APIs and convert between
UTF-8/UTF-16.

Removes parameter checks that are already covered by xutftowcs_path. This
changes detection of ENAMETOOLONG from MAX_PATH - 2 to MAX_PATH (matching
is_dir_empty in mingw.c). If name + "/*" or the resulting absolute path is
too long, FindFirstFile fails and errno is set through err_win_to_posix.

Increases the size of dirent.d_name to accommodate the full
WIN32_FIND_DATA.cFileName converted to UTF-8 (UTF-16 to UTF-8 conversion
may grow by factor three in the worst case).

Signed-off-by: Karsten Blees 
---
 compat/win32/dirent.c | 30 ++++++++++--------------------
 compat/win32/dirent.h |  2 +-
 2 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 82a515c21b..52420ec7d4 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -6,10 +6,10 @@ struct DIR {
 	int dd_stat;          /* 0-based index */
 };
 
-static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
 {
-	/* copy file name from WIN32_FIND_DATA to dirent */
-	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+	/* convert UTF-16 name to UTF-8 */
+	xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
 
 	/* Set file type, based on WIN32_FIND_DATA */
 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -20,25 +20,15 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
 
 DIR *opendir(const char *name)
 {
-	char pattern[MAX_PATH];
-	WIN32_FIND_DATAA fdata;
+	wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
+	WIN32_FIND_DATAW fdata;
 	HANDLE h;
 	int len;
 	DIR *dir;
 
-	/* check that name is not NULL */
-	if (!name) {
-		errno = EINVAL;
+	/* convert name to UTF-16 and check length < MAX_PATH */
+	if ((len = xutftowcs_path(pattern, name)) < 0)
 		return NULL;
-	}
-	/* check that the pattern won't be too long for FindFirstFileA */
-	len = strlen(name);
-	if (len + 2 >= MAX_PATH) {
-		errno = ENAMETOOLONG;
-		return NULL;
-	}
-	/* copy name to temp buffer */
-	memcpy(pattern, name, len + 1);
 
 	/* append optional '/' and wildcard '*' */
 	if (len && !is_dir_sep(pattern[len - 1]))
@@ -47,7 +37,7 @@ DIR *opendir(const char *name)
 	pattern[len] = 0;
 
 	/* open find handle */
-	h = FindFirstFileA(pattern, &fdata);
+	h = FindFirstFileW(pattern, &fdata);
 	if (h == INVALID_HANDLE_VALUE) {
 		DWORD err = GetLastError();
 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
@@ -72,8 +62,8 @@ struct dirent *readdir(DIR *dir)
 	/* if first entry, dirent has already been set up by opendir */
 	if (dir->dd_stat) {
 		/* get next entry and convert from WIN32_FIND_DATA to dirent */
-		WIN32_FIND_DATAA fdata;
-		if (FindNextFileA(dir->dd_handle, &fdata)) {
+		WIN32_FIND_DATAW fdata;
+		if (FindNextFileW(dir->dd_handle, &fdata)) {
 			finddata2dirent(&dir->dd_dir, &fdata);
 		} else {
 			DWORD lasterr = GetLastError();
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 8838cd61fc..058207e4bf 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,7 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
-	char d_name[MAX_PATH];     /* file name */
+	char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
 };
 
 DIR *opendir(const char *dirname);

From 1fbcf13ee32b1963e8470f497d9fa0502870fe37 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 4 Feb 2012 21:54:36 +0100
Subject: [PATCH 2994/3720] Unicode file name support (gitk and git-gui)

Assumes file names in git tree objects are UTF-8 encoded.

On most unix systems, the system encoding (and thus the TCL system
encoding) will be UTF-8, so file names will be displayed correctly.

On Windows, it is impossible to set the system encoding to UTF-8. Changing
the TCL system encoding (via 'encoding system ...', e.g. in the startup
code) is explicitly discouraged by the TCL docs.

Change gitk and git-gui functions dealing with file names to always convert
from and to UTF-8.

Signed-off-by: Karsten Blees 
---
 git-gui/git-gui.sh      | 11 +++++++----
 git-gui/lib/browser.tcl |  2 +-
 git-gui/lib/index.tcl   |  6 +++---
 gitk-git/gitk           | 16 ++++++++--------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index a59020bcc5..e5038ddd12 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -533,6 +533,9 @@ proc git {args} {
 
 	_trace_exec [concat $opt $cmdp $args]
 	set result [eval exec $opt $cmdp $args]
+	if {[encoding system] != "utf-8"} {
+		set result [encoding convertfrom utf-8 [encoding convertto $result]]
+	}
 	if {$::_trace} {
 		puts stderr "< $result"
 	}
@@ -1087,7 +1090,7 @@ git-version proc _parse_config {arr_name args} {
 				[list git_read config] \
 				$args \
 				[list --null --list]]
-			fconfigure $fd_rc -translation binary
+			fconfigure $fd_rc -translation binary -encoding utf-8
 			set buf [read $fd_rc]
 			close $fd_rc
 		}
@@ -1652,7 +1655,7 @@ proc read_diff_index {fd after} {
 		set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			[lindex $i 4]? \
 			[list [lindex $i 0] [lindex $i 2]] \
 			[list]
@@ -1685,7 +1688,7 @@ proc read_diff_files {fd after} {
 		set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			?[lindex $i 4] \
 			[list] \
 			[list [lindex $i 0] [lindex $i 2]]
@@ -1708,7 +1711,7 @@ proc read_ls_others {fd after} {
 	set pck [split $buf_rlo "\0"]
 	set buf_rlo [lindex $pck end]
 	foreach p [lrange $pck 0 end-1] {
-		set p [encoding convertfrom $p]
+		set p [encoding convertfrom utf-8 $p]
 		if {[string index $p end] eq {/}} {
 			set p [string range $p 0 end-1]
 		}
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 4fca8fb13c..555db896f4 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary
+	fconfigure $fd -blocking 0 -translation binary -encoding utf-8
 	fileevent $fd readable [cb _read $fd]
 }
 
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdde21..6ca0a6e369 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -115,7 +115,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
 		set info [lindex $s 2]
 		if {$info eq {}} continue
 
-		puts -nonewline $fd "$info\t[encoding convertto $path]\0"
+		puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -186,7 +186,7 @@ proc write_update_index {fd pathList totalCnt batch after} {
 		?M {set new M_}
 		?? {continue}
 		}
-		puts -nonewline $fd "[encoding convertto $path]\0"
+		puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -247,7 +247,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
 		?M -
 		?T -
 		?D {
-			puts -nonewline $fd "[encoding convertto $path]\0"
+			puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 			display_file $path ?_
 		}
 		}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 3660096db5..f9e936d69e 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7288,7 +7288,7 @@ proc gettreeline {gtf id} {
 	if {[string index $fname 0] eq "\""} {
 	    set fname [lindex $fname 0]
 	}
-	set fname [encoding convertfrom $fname]
+	set fname [encoding convertfrom utf-8 $fname]
 	lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -7507,7 +7507,7 @@ proc gettreediffline {gdtf ids} {
 	    if {[string index $file 0] eq "\""} {
 		set file [lindex $file 0]
 	    }
-	    set file [encoding convertfrom $file]
+	    set file [encoding convertfrom utf-8 $file]
 	    if {$file ne [lindex $treediff end]} {
 		lappend treediff $file
 		lappend sublist $file
@@ -7656,7 +7656,7 @@ proc makediffhdr {fname ids} {
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -7690,7 +7690,7 @@ proc getblobdiffline {bdf ids} {
 	}
 	if {![string compare -length 5 "diff " $line]} {
 	    if {![regexp {^diff (--cc|--git) } $line m type]} {
-		set line [encoding convertfrom $line]
+		set line [encoding convertfrom utf-8 $line]
 		$ctext insert end "$line\n" hunksep
 		continue
 	    }
@@ -7737,7 +7737,7 @@ proc getblobdiffline {bdf ids} {
 	    makediffhdr $fname $ids
 
 	} elseif {![string compare -length 16 "* Unmerged path " $line]} {
-	    set fname [encoding convertfrom [string range $line 16 end]]
+	    set fname [encoding convertfrom utf-8 [string range $line 16 end]]
 	    $ctext insert end "\n"
 	    set curdiffstart [$ctext index "end - 1c"]
 	    lappend ctext_file_names $fname
@@ -7792,7 +7792,7 @@ proc getblobdiffline {bdf ids} {
 		if {[string index $fname 0] eq "\""} {
 		    set fname [lindex $fname 0]
 		}
-		set fname [encoding convertfrom $fname]
+		set fname [encoding convertfrom utf-8 $fname]
 		set i [lsearch -exact $treediffs($ids) $fname]
 		if {$i >= 0} {
 		    setinlist difffilestart $i $curdiffstart
@@ -7811,7 +7811,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
-	    set line [encoding convertfrom $line]
+	    set line [encoding convertfrom utf-8 $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {
@@ -11460,7 +11460,7 @@ proc cache_gitattr {attr pathlist} {
 	    foreach row [split $rlist "\n"] {
 		if {[regexp "(.*): $attr: (.*)" $row m path value]} {
 		    if {[string index $path 0] eq "\""} {
-			set path [encoding convertfrom [lindex $path 0]]
+			set path [encoding convertfrom utf-8 [lindex $path 0]]
 		    }
 		    set path_attr_cache($attr,$path) $value
 		}

From 9f5a7be56797ba1cae5459940f5fb693e6b286c5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:27:53 +0100
Subject: [PATCH 2995/3720] Win32: Unicode arguments (outgoing)

Convert command line arguments from UTF-8 to UTF-16 when creating other
processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 5d5f30bd2c..de0a55fe84 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -955,9 +955,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFO si;
+	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
 	struct strbuf envblk, args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
 	unsigned flags;
 	BOOL ret;
 
@@ -993,6 +994,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	si.hStdOutput = winansi_get_osfhandle(fhout);
 	si.hStdError = winansi_get_osfhandle(fherr);
 
+	if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
 	if (prepend_cmd) {
@@ -1010,6 +1016,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			free(quoted);
 	}
 
+	wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
@@ -1031,12 +1041,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	}
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir, &si, &pi);
+	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
 	if (env)
 		strbuf_release(&envblk);
-	strbuf_release(&args);
+	free(wargs);
 
 	if (!ret) {
 		errno = ENOENT;

From cc9c06f938d3ea698e0d49455a21c06e7f608595 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:28:27 +0100
Subject: [PATCH 2996/3720] Win32: Unicode arguments (incoming)

Convert command line arguments from UTF-16 to UTF-8 on startup.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index de0a55fe84..428c056009 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2040,10 +2040,41 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
  */
 int _CRT_glob = 0;
 
+typedef struct {
+	int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+		_startupinfo *si);
+
 void mingw_startup()
 {
-	/* copy executable name to argv[0] */
-	__argv[0] = xstrdup(_pgmptr);
+	int i, len, maxlen, argc;
+	char *buffer;
+	wchar_t **wenv, **wargv;
+	_startupinfo si;
+
+	/* get wide char arguments and environment */
+	si.newmode = 0;
+	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(_wpgmptr);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = xmalloc(maxlen);
+
+	/* convert command line arguments and environment to UTF-8 */
+	len = xwcstoutf(buffer, _wpgmptr, maxlen);
+	__argv[0] = xmemdupz(buffer, len);
+	for (i = 1; i < argc; i++) {
+		len = xwcstoutf(buffer, wargv[i], maxlen);
+		__argv[i] = xmemdupz(buffer, len);
+	}
+	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);

From c35cf1a287a26451d880c3f166f4c29a11bc8d5f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:17:49 +0100
Subject: [PATCH 2997/3720] Win32: sync Unicode console output and file system

Use the same Unicode conversion functions for file names and console
conversions so that the file system and console output are in sync when
checking out legacy encoded repositories (i.e. with invalid UTF-8 file
names).

Signed-off-by: Karsten Blees 
---
 compat/winansi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a3e4d88295..9f95954390 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -120,8 +120,7 @@ static void write_console(unsigned char *str, size_t len)
 	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
 
 	/* convert utf-8 to utf-16 */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
-			ARRAY_SIZE(wbuf));
+	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);

From b793bedbbce5b25be28b3465ef60ee9c4600dced Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:07:46 +0100
Subject: [PATCH 2998/3720] Win32: Unicode environment (outgoing)

Convert environment from UTF-8 to UTF-16 when creating other processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 428c056009..d78ac239e0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -957,9 +957,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 {
 	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
-	struct strbuf envblk, args;
-	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
-	unsigned flags;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 
 	/* Determine whether or not we are associated to a console */
@@ -976,7 +976,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * instead of CREATE_NO_WINDOW to make ssh
 		 * recognize that it has no console.
 		 */
-		flags = DETACHED_PROCESS;
+		flags |= DETACHED_PROCESS;
 	} else {
 		/* There is already a console. If we specified
 		 * DETACHED_PROCESS here, too, Windows would
@@ -984,7 +984,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * The same is true for CREATE_NO_WINDOW.
 		 * Go figure!
 		 */
-		flags = 0;
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
@@ -1023,6 +1022,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
+		int size = 0, wenvsz = 0, wenvpos = 0;
 
 		for (e = env; *e; e++)
 			count++;
@@ -1032,20 +1032,22 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
 		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
 
-		strbuf_init(&envblk, 0);
+		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
-			strbuf_addstr(&envblk, *e);
-			strbuf_addch(&envblk, '\0');
+			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
 		}
+		/* add final \0 terminator */
+		wenvblk[wenvpos] = 0;
 		free(sorted_env);
 	}
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
+		wenvblk, dir ? wdir : NULL, &si, &pi);
 
-	if (env)
-		strbuf_release(&envblk);
+	free(wenvblk);
 	free(wargs);
 
 	if (!ret) {

From f570f5b6135fe61447a04c21e3cb563327c6ac59 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 25 Apr 2011 23:32:27 +0100
Subject: [PATCH 2999/3720] Win32: Unicode environment (incoming)

Convert environment from UTF-16 to UTF-8 on startup.

No changes to getenv() are necessary, as the MSVCRT version is implemented
on top of char **environ.

However, putenv / _wputenv from MSVCRT no longer work, for two reasons:
1. they try to keep environ, _wenviron and the Win32 process environment
in sync, using the default system encoding instead of UTF-8 to convert
between charsets
2. msysgit and MSVCRT use different allocators, memory allocated in git
cannot be freed by the CRT and vice versa

Implement mingw_putenv using the env_setenv helper function from the
environment merge code.

Note that in case of memory allocation failure, putenv now dies with error
message (due to xrealloc) instead of failing with ENOMEM. As git assumes
setenv / putenv to always succeed, this prevents it from continuing with
incorrect settings.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index d78ac239e0..fe1d0de81f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1282,6 +1282,12 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -2064,6 +2070,11 @@ void mingw_startup()
 	maxlen = wcslen(_wpgmptr);
 	for (i = 1; i < argc; i++)
 		maxlen = max(maxlen, wcslen(wargv[i]));
+	for (i = 0; wenv[i]; i++)
+		maxlen = max(maxlen, wcslen(wenv[i]));
+
+	/* nedmalloc can't free CRT memory, allocate resizable environment list */
+	environ = xcalloc(i + 1, sizeof(char*));
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2076,6 +2087,10 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wargv[i], maxlen);
 		__argv[i] = xmemdupz(buffer, len);
 	}
+	for (i = 0; wenv[i]; i++) {
+		len = xwcstoutf(buffer, wenv[i], maxlen);
+		environ[i] = xmemdupz(buffer, len);
+	}
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
diff --git a/compat/mingw.h b/compat/mingw.h
index ea8c1f8993..af1574c435 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -200,6 +200,8 @@ char *mingw_getcwd(char *pointer, int len);
 
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
+int mingw_putenv(const char *namevalue);
+#define putenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From e1aa330f160c9993b7b3f2b20df7755ff67e3d5d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 20 Aug 2011 14:27:02 +0200
Subject: [PATCH 3000/3720] MinGW: disable legacy encoding tests

On Windows, all native APIs are Unicode-based. It is impossible to pass
legacy encoded byte arrays to a process via command line or environment
variables. Disable the tests that try to do so.

In t3901, most tests still work if we don't mess up the repository encoding
in setup, so don't switch to ISO-8859-1 on MinGW.

Note that i18n tests that do their encoding tricks via encoded files (such
as t3900) are not affected by this.

Signed-off-by: Karsten Blees 
---
 t/t3901-i18n-patch.sh | 19 +++++++++++--------
 t/t4201-shortlog.sh   |  6 +++---
 t/t8005-blame-i18n.sh |  8 ++++----
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 31a5770b34..55c8a2f576 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -54,10 +54,13 @@ test_expect_success setup '
 	git add yours &&
 	git commit -s -m "Second on side" &&
 
-	# the second one on the side branch is ISO-8859-1
-	git config i18n.commitencoding ISO8859-1 &&
-	# use author and committer name in ISO-8859-1 to match it.
-	. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+	if test_have_prereq NOT_MINGW
+	then
+		# the second one on the side branch is ISO-8859-1
+		git config i18n.commitencoding ISO8859-1 &&
+		# use author and committer name in ISO-8859-1 to match it.
+		. "$TEST_DIRECTORY"/t3901-8859-1.txt
+	fi &&
 	test_tick &&
 	echo Yet another >theirs &&
 	git add theirs &&
@@ -119,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
 	check_encoding 2
 '
 
-test_expect_success 'rebase (L/L)' '
+test_expect_success NOT_MINGW 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
 	git config i18n.commitencoding ISO8859-1 &&
 	git config i18n.logoutputencoding ISO8859-1 &&
@@ -131,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 	check_encoding 2 8859
 '
 
-test_expect_success 'rebase (L/U)' '
+test_expect_success NOT_MINGW 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
 	git config i18n.commitencoding ISO8859-1 &&
@@ -159,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/L)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
 	git config i18n.commitencoding ISO8859-1 &&
@@ -189,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/U)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6872ba1a42..48963811bf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
 	test_cmp expect log.predictable
 '
 
-test_expect_success 'shortlog wrapping' '
+test_expect_success NOT_MINGW 'shortlog wrapping' '
 	cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
 	test_cmp expect out
 '
 
-test_expect_success 'shortlog from non-git directory' '
+test_expect_success NOT_MINGW 'shortlog from non-git directory' '
 	git log HEAD >log &&
 	GIT_DIR=non-existing git shortlog -w out &&
 	test_cmp expect out
@@ -135,7 +135,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success 'shortlog encoding' '
+test_expect_success NOT_MINGW 'shortlog encoding' '
 	git reset --hard "$commit" &&
 	git config --unset i18n.commitencoding &&
 	echo 2 > a1 &&
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index cb390559f9..a6e73d0635 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.commitencoding' '
 	git blame --incremental file | \
 		egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.logoutputencoding' '
 	git config i18n.logoutputencoding eucJP &&
 	git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=UTF-8' '
 	git blame --incremental --encoding=UTF-8 file | \
 		egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=none' '
 	git blame --incremental --encoding=none file | \
 		egrep "^(author|summary) " > actual &&

From e2054edcf7f179f589b4905bf83dee77eba9779e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:29:40 +0100
Subject: [PATCH 3001/3720] Win32: fix environment memory leaks

All functions that modify the environment have memory leaks.

Disable gitunsetenv in the Makefile and use env_setenv (via mingw_putenv)
instead (this frees removed environment entries).

Move xstrdup from env_setenv to make_augmented_environ, so that
mingw_putenv no longer copies the environment entries (according to POSIX
[1], "the string [...] shall become part of the environment"). This also
fixes the memory leak in gitsetenv, which expects a POSIX compliant putenv.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html

Note: This patch depends on taking control of char **environ and having
our own mingw_putenv (both introduced in "Win32: Unicode environment
(incoming)").

Signed-off-by: Karsten Blees 
---
 Makefile       |  2 --
 compat/mingw.c | 10 ++++++----
 compat/mingw.h |  1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 63785ee9f6..7d36d73949 100644
--- a/Makefile
+++ b/Makefile
@@ -1159,7 +1159,6 @@ ifeq ($(uname_S),Windows)
 	NO_IPV6 = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
@@ -1256,7 +1255,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SYMLINK_HEAD = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index fe1d0de81f..bbd35d8bd4 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1255,14 +1255,14 @@ static char **env_setenv(char **env, const char *name)
 			for (i = 0; env[i]; i++)
 				;
 			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 			env[i+1] = NULL;
 		}
 	}
 	else {
 		free(env[i]);
 		if (*eq)
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 		else
 			for (; env[i]; i++)
 				env[i] = env[i+1];
@@ -1277,8 +1277,10 @@ char **make_augmented_environ(const char *const *vars)
 {
 	char **env = copy_environ();
 
-	while (*vars)
-		env = env_setenv(env, *vars++);
+	while (*vars) {
+		const char *v = *vars++;
+		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+	}
 	return env;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index af1574c435..ba21474515 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -202,6 +202,7 @@ char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 int mingw_putenv(const char *namevalue);
 #define putenv mingw_putenv
+#define unsetenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From a809fe2176d6aebc2e876a27b815d44b2ced88cc Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 23:42:09 +0100
Subject: [PATCH 3002/3720] Win32: unify environment case-sensitivity

The environment on Windows is case-insensitive. Some environment functions
(such as unsetenv and make_augmented_environ) have always used case-
sensitive comparisons instead, while others (getenv, putenv, sorting in
spawn*) were case-insensitive.

Prevent potential inconsistencies by using case-insensitive comparison in
lookup_env (used by putenv, unsetenv and make_augmented_environ).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bbd35d8bd4..bef2f3314e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1234,8 +1234,7 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 	int i;
 
 	for (i = 0; env[i]; i++) {
-		if (0 == strncmp(env[i], name, nmln)
-		    && '=' == env[i][nmln])
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
 			/* matches */
 			return i;
 	}

From 7ef917e50b0b2cba478169712ad144f53d204276 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:33:17 +0100
Subject: [PATCH 3003/3720] Win32: simplify internal mingw_spawn* APIs

The only public spawn function that needs to tweak the environment is
mingw_spawnvpe (called from start_command). Nevertheless, all internal
spawn* functions take an env parameter and needlessly pass the global
char **environ around. Remove the env parameter where it's not needed.

This removes the internal mingw_execve abstraction, which is no longer
needed.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bef2f3314e..311a1832d0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1077,10 +1077,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-			   int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -1122,7 +1121,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 	return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
 	const char *interpr = parse_interpreter(cmd);
 	char **path;
@@ -1140,7 +1139,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 		argv2 = xmalloc(sizeof(*argv) * (argc+1));
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-		pid = mingw_spawnve(prog, argv2, env, 1);
+		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -1155,13 +1154,13 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 	return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+void mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
-	if (!try_shell_exec(cmd, argv, (char **)env)) {
+	if (!try_shell_exec(cmd, argv)) {
 		int pid, status;
 
-		pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
 			return;
 		if (waitpid(pid, &status, 0) < 0)
@@ -1176,7 +1175,7 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	char *prog = path_lookup(cmd, path, 0);
 
 	if (prog) {
-		mingw_execve(prog, argv, environ);
+		mingw_execv(prog, argv);
 		free(prog);
 	} else
 		errno = ENOENT;
@@ -1184,11 +1183,6 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	free_path_split(path);
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
-{
-	mingw_execve(cmd, argv, environ);
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
 	if (pid > 0 && sig == SIGTERM) {

From b990b8a7d7e643fd8367e528b74dbf021a570921 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:05:04 +0100
Subject: [PATCH 3004/3720] Win32: move environment functions

Move environment helper functions up so that they can be reused by
mingw_getenv and mingw_spawnve_fd in subsequent patches.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 106 ++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 311a1832d0..0c406669df 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,6 +737,53 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
+static int env_compare(const void *a, const void *b)
+{
+	char *const *ea = a;
+	char *const *eb = b;
+	return strcasecmp(*ea, *eb);
+}
+
+static int lookup_env(char **env, const char *name, size_t nmln)
+{
+	int i;
+
+	for (i = 0; env[i]; i++) {
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
+			/* matches */
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * If name contains '=', then sets the variable, otherwise it unsets it
+ */
+static char **env_setenv(char **env, const char *name)
+{
+	char *eq = strchrnul(name, '=');
+	int i = lookup_env(env, name, eq-name);
+
+	if (i < 0) {
+		if (*eq) {
+			for (i = 0; env[i]; i++)
+				;
+			env = xrealloc(env, (i+2)*sizeof(*env));
+			env[i] = (char*) name;
+			env[i+1] = NULL;
+		}
+	}
+	else {
+		free(env[i]);
+		if (*eq)
+			env[i] = (char*) name;
+		else
+			for (; env[i]; i++)
+				env[i] = env[i+1];
+	}
+	return env;
+}
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -754,6 +801,12 @@ char *mingw_getenv(const char *name)
 	return result;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -936,13 +989,6 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
-static int env_compare(const void *a, const void *b)
-{
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
-}
-
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1223,46 +1269,6 @@ void free_environ(char **env)
 	free(env);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
-{
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
-	}
-	return -1;
-}
-
-/*
- * If name contains '=', then sets the variable, otherwise it unsets it
- */
-static char **env_setenv(char **env, const char *name)
-{
-	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
-
-	if (i < 0) {
-		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
-		}
-	}
-	else {
-		free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-	}
-	return env;
-}
-
 /*
  * Copies global environ and adjusts variables as specified by vars.
  */
@@ -1277,12 +1283,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-int mingw_putenv(const char *namevalue)
-{
-	environ = env_setenv(environ, namevalue);
-	return 0;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 05d7ec8ea5933cb22853264b54c9ddde0b49a3d7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Wed, 5 Oct 2011 22:01:46 +0200
Subject: [PATCH 3005/3720] Win32: unify environment function names

Environment helper functions use random naming ('env' prefix or suffix or
both, with or without '_'). Change to POSIX naming scheme ('env' suffix,
no '_').

Env_setenv has more in common with putenv than setenv. Change to do_putenv.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0c406669df..e5d8c6a438 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,14 +737,14 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int env_compare(const void *a, const void *b)
+static int compareenv(const void *a, const void *b)
 {
 	char *const *ea = a;
 	char *const *eb = b;
 	return strcasecmp(*ea, *eb);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
+static int lookupenv(char **env, const char *name, size_t nmln)
 {
 	int i;
 
@@ -759,10 +759,10 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **env_setenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name)
 {
 	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
+	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
@@ -803,7 +803,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = env_setenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue);
 	return 0;
 }
 
@@ -1076,7 +1076,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		/* environment must be sorted */
 		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
 
 		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
@@ -1278,7 +1278,7 @@ char **make_augmented_environ(const char *const *vars)
 
 	while (*vars) {
 		const char *v = *vars++;
-		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
 	}
 	return env;
 }

From 2ad7af6375da33296cb2459888a92c63719121bb Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:31:57 +0100
Subject: [PATCH 3006/3720] Win32: factor out environment block creation

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 55 +++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e5d8c6a438..be381573f1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -989,6 +989,36 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
+/*
+ * Create environment block suitable for CreateProcess.
+ */
+static wchar_t *make_environment_block(char **env)
+{
+	wchar_t *wenvblk = NULL;
+	int count = 0;
+	char **e, **tmpenv;
+	int size = 0, wenvsz = 0, wenvpos = 0;
+
+	for (e = env; *e; e++)
+		count++;
+
+	/* environment must be sorted */
+	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+
+	/* create environment block from temporary environment */
+	for (e = tmpenv; *e; e++) {
+		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+	}
+	/* add final \0 terminator */
+	wenvblk[wenvpos] = 0;
+	free(tmpenv);
+	return wenvblk;
+}
+
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1065,29 +1095,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env) {
-		int count = 0;
-		char **e, **sorted_env;
-		int size = 0, wenvsz = 0, wenvpos = 0;
-
-		for (e = env; *e; e++)
-			count++;
-
-		/* environment must be sorted */
-		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
-		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
-
-		/* create environment block from temporary environment */
-		for (e = sorted_env; *e; e++) {
-			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
-			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
-		}
-		/* add final \0 terminator */
-		wenvblk[wenvpos] = 0;
-		free(sorted_env);
-	}
+	if (env)
+		wenvblk = make_environment_block(env);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,

From b370c2e1731d3598cce8a97fb4a6e3d808ad7eac Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:57:14 +0100
Subject: [PATCH 3007/3720] Win32: don't copy the environment twice when
 spawning child processes

When spawning child processes via start_command(), the environment and all
environment entries are copied twice. First by make_augmented_environ /
copy_environ to merge with child_process.env. Then a second time by
make_environment_block to create a sorted environment block string as
required by CreateProcess.

Move the merge logic to make_environment_block so that we only need to copy
the environment once. This changes semantics of the env parameter: it now
expects a delta (such as child_process.env) rather than a full environment.
This is not a problem as the parameter is only used by start_command()
(all other callers previously passed char **environ, and now pass NULL).

The merge logic no longer xstrdup()s the environment strings, so do_putenv
must not free them. Add a parameter to distinguish this from normal putenv.

Remove the now unused make_augmented_environ / free_environ API.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 74 ++++++++++++++++----------------------------------
 compat/mingw.h |  6 ----
 run-command.c  | 10 ++-----
 3 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index be381573f1..9a0b39a47e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -759,7 +759,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **do_putenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
@@ -774,7 +774,8 @@ static char **do_putenv(char **env, const char *name)
 		}
 	}
 	else {
-		free(env[i]);
+		if (free_old)
+			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
 		else
@@ -803,7 +804,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue, 1);
 	return 0;
 }
 
@@ -990,21 +991,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 }
 
 /*
- * Create environment block suitable for CreateProcess.
+ * Create environment block suitable for CreateProcess. Merges current
+ * process environment and the supplied environment changes.
  */
-static wchar_t *make_environment_block(char **env)
+static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
 	int count = 0;
 	char **e, **tmpenv;
 	int size = 0, wenvsz = 0, wenvpos = 0;
 
-	for (e = env; *e; e++)
+	while (environ[count])
 		count++;
 
-	/* environment must be sorted */
+	/* copy the environment */
 	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+
+	/* merge supplied environment changes into the temporary environment */
+	for (e = deltaenv; e && *e; e++)
+		tmpenv = do_putenv(tmpenv, *e, 0);
+
+	/* environment must be sorted */
+	for (count = 0; tmpenv[count]; )
+		count++;
 	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
 
 	/* create environment block from temporary environment */
@@ -1027,7 +1037,7 @@ struct pinfo_t {
 struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
-static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
@@ -1095,8 +1105,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env)
-		wenvblk = make_environment_block(env);
+	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1134,10 +1143,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
 static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 		     const char *dir,
 		     int fhin, int fhout, int fherr)
 {
@@ -1161,14 +1170,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 				pid = -1;
 			}
 			else {
-				pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
 						       fhin, fhout, fherr);
 				free(iprog);
 			}
 			argv[0] = argv0;
 		}
 		else
-			pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
 					       fhin, fhout, fherr);
 		free(prog);
 	}
@@ -1257,41 +1266,6 @@ int mingw_kill(pid_t pid, int sig)
 	return -1;
 }
 
-static char **copy_environ(void)
-{
-	char **env;
-	int i = 0;
-	while (environ[i])
-		i++;
-	env = xmalloc((i+1)*sizeof(*env));
-	for (i = 0; environ[i]; i++)
-		env[i] = xstrdup(environ[i]);
-	env[i] = NULL;
-	return env;
-}
-
-void free_environ(char **env)
-{
-	int i;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-/*
- * Copies global environ and adjusts variables as specified by vars.
- */
-char **make_augmented_environ(const char *const *vars)
-{
-	char **env = copy_environ();
-
-	while (*vars) {
-		const char *v = *vars++;
-		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
-	}
-	return env;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
diff --git a/compat/mingw.h b/compat/mingw.h
index ba21474515..04b6523255 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -335,12 +335,6 @@ void mingw_open_html(const char *path);
 void mingw_mark_as_git_dir(const char *dir);
 #define mark_as_git_dir mingw_mark_as_git_dir
 
-/*
- * helpers
- */
-
-char **make_augmented_environ(const char *const *vars);
-void free_environ(char **env);
 
 /**
  * Converts UTF-8 encoded string to UTF-16LE.
diff --git a/run-command.c b/run-command.c
index 1db8abf984..6d0dc3da91 100644
--- a/run-command.c
+++ b/run-command.c
@@ -381,7 +381,6 @@ fail_pipe:
 {
 	int fhin = 0, fhout = 1, fherr = 2;
 	const char **sargv = cmd->argv;
-	char **env = environ;
 
 	if (cmd->no_stdin)
 		fhin = open("/dev/null", O_RDWR);
@@ -406,25 +405,20 @@ fail_pipe:
 	else if (cmd->out > 1)
 		fhout = dup(cmd->out);
 
-	if (cmd->env)
-		env = make_augmented_environ(cmd->env);
-
 	if (cmd->git_cmd) {
 		cmd->argv = prepare_git_cmd(cmd->argv);
 	} else if (cmd->use_shell) {
 		cmd->argv = prepare_shell_cmd(cmd->argv);
 	}
 
-	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
-				  fhin, fhout, fherr);
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
 	failed_errno = errno;
 	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 		error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 	if (cmd->clean_on_exit && cmd->pid >= 0)
 		mark_child_for_cleanup(cmd->pid);
 
-	if (cmd->env)
-		free_environ(env);
 	if (cmd->git_cmd)
 		free(cmd->argv);
 

From b082e9a55d47e3d5f3d3286a954154ceebb7ebb2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:00:35 +0100
Subject: [PATCH 3008/3720] Win32: reduce environment array reallocations

Move environment array reallocation from do_putenv to the respective
callers. Keep track of the environment size in a global variable. Use
ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a
sufficiently sized environment array in make_environment_block to prevent
reallocations.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 60 ++++++++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9a0b39a47e..2d984bd8d3 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -758,19 +758,19 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
+ * Size includes the terminating NULL. Env must have room for size + 1 entries
+ * (in case of insert). Returns the new size. Optionally frees removed entries.
  */
-static char **do_putenv(char **env, const char *name, int free_old)
+static int do_putenv(char **env, const char *name, int size, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
+			env[size - 1] = (char*) name;
+			env[size] = NULL;
+			size++;
 		}
 	}
 	else {
@@ -778,13 +778,20 @@ static char **do_putenv(char **env, const char *name, int free_old)
 			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
-		else
+		else {
 			for (; env[i]; i++)
 				env[i] = env[i+1];
+			size--;
+		}
 	}
-	return env;
+	return size;
 }
 
+/* used number of elements of environ array, including terminating NULL */
+static int environ_size = 0;
+/* allocated size of environ array, in bytes */
+static int environ_alloc = 0;
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -804,7 +811,8 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue, 1);
+	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
+	environ_size = do_putenv(environ, namevalue, environ_size, 1);
 	return 0;
 }
 
@@ -997,31 +1005,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
-	int count = 0;
-	char **e, **tmpenv;
-	int size = 0, wenvsz = 0, wenvpos = 0;
+	char **tmpenv;
+	int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
 
-	while (environ[count])
-		count++;
+	while (deltaenv && deltaenv[i])
+		i++;
 
-	/* copy the environment */
-	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+	/* copy the environment, leaving space for changes */
+	tmpenv = xmalloc((size + i) * sizeof(char*));
+	memcpy(tmpenv, environ, size * sizeof(char*));
 
 	/* merge supplied environment changes into the temporary environment */
-	for (e = deltaenv; e && *e; e++)
-		tmpenv = do_putenv(tmpenv, *e, 0);
+	for (i = 0; deltaenv && deltaenv[i]; i++)
+		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
 	/* environment must be sorted */
-	for (count = 0; tmpenv[count]; )
-		count++;
-	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
 
 	/* create environment block from temporary environment */
-	for (e = tmpenv; *e; e++) {
-		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+	for (i = 0; tmpenv[i]; i++) {
+		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
 		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+		wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
 	}
 	/* add final \0 terminator */
 	wenvblk[wenvpos] = 0;
@@ -2052,7 +2057,9 @@ void mingw_startup()
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
 	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = xcalloc(i + 1, sizeof(char*));
+	environ = NULL;
+	environ_size = i + 1;
+	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2069,6 +2076,7 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wenv[i], maxlen);
 		environ[i] = xmemdupz(buffer, len);
 	}
+	environ[i] = NULL;
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */

From a4240ee1f919cf69e3c1fe3bbb1e627ae157af98 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:30:02 +0100
Subject: [PATCH 3009/3720] Win32: keep the environment sorted

The Windows environment is sorted, keep it that way for O(log n)
environment access.

Change compareenv to compare only the keys, so that it can be used to
find an entry irrespective of the value.

Change lookupenv to binary seach for an entry. Return one's complement of
the insert position if not found (libc's bsearch returns NULL).

Replace MSVCRT's getenv with a minimal do_getenv based on the binary search
function.

Change do_putenv to insert new entries at the correct position. Simplify
the function by swapping if conditions and using memmove instead of for
loops.

Move qsort from make_environment_block to mingw_startup. We still need to
sort on startup to make sure that the environment is sorted according to
our compareenv function (while Win32 / CreateProcess requires the
environment block to be sorted case-insensitively, CreateProcess currently
doesn't enforce this, and some applications such as bash just don't care).

Note that environment functions are _not_ thread-safe and are not required
to be so by POSIX, the application is responsible for synchronizing access
to the environment. MSVCRT's getenv and our new getenv implementation are
better than that in that they are thread-safe with respect to other getenv
calls as long as the environment is not modified. Git's indiscriminate use
of getenv in background threads currently requires this property.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 98 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 62 insertions(+), 36 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2d984bd8d3..b569faf0b0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,23 +737,42 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int compareenv(const void *a, const void *b)
+/*
+ * Compare environment entries by key (i.e. stopping at '=' or '\0').
+ */
+static int compareenv(const void *v1, const void *v2)
 {
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
+	const char *e1 = *(const char**)v1;
+	const char *e2 = *(const char**)v2;
+
+	for (;;) {
+		int c1 = *e1++;
+		int c2 = *e2++;
+		c1 = (c1 == '=') ? 0 : tolower(c1);
+		c2 = (c2 == '=') ? 0 : tolower(c2);
+		if (c1 > c2)
+			return 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 == 0)
+			return 0;
+	}
 }
 
-static int lookupenv(char **env, const char *name, size_t nmln)
+static int bsearchenv(char **env, const char *name, size_t size)
 {
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
+	unsigned low = 0, high = size;
+	while (low < high) {
+		unsigned mid = low + ((high - low) >> 1);
+		int cmp = compareenv(&env[mid], &name);
+		if (cmp < 0)
+			low = mid + 1;
+		else if (cmp > 0)
+			high = mid;
+		else
+			return mid;
 	}
-	return -1;
+	return ~low; /* not found, return 1's complement of insert position */
 }
 
 /*
@@ -763,26 +782,24 @@ static int lookupenv(char **env, const char *name, size_t nmln)
  */
 static int do_putenv(char **env, const char *name, int size, int free_old)
 {
-	char *eq = strchrnul(name, '=');
-	int i = lookupenv(env, name, eq-name);
+	int i = bsearchenv(env, name, size - 1);
 
-	if (i < 0) {
-		if (*eq) {
-			env[size - 1] = (char*) name;
-			env[size] = NULL;
+	/* optionally free removed / replaced entry */
+	if (i >= 0 && free_old)
+		free(env[i]);
+
+	if (strchr(name, '=')) {
+		/* if new value ('key=value') is specified, insert or replace entry */
+		if (i < 0) {
+			i = ~i;
+			memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
 			size++;
 		}
-	}
-	else {
-		if (free_old)
-			free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else {
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-			size--;
-		}
+		env[i] = (char*) name;
+	} else if (i >= 0) {
+		/* otherwise ('key') remove existing entry */
+		size--;
+		memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
 	}
 	return size;
 }
@@ -792,15 +809,24 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-#undef getenv
+static char *do_getenv(const char *name)
+{
+	char *value;
+	int pos = bsearchenv(environ, name, environ_size - 1);
+	if (pos < 0)
+		return NULL;
+	value = strchr(environ[pos], '=');
+	return value ? &value[1] : NULL;
+}
+
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv(name);
+	char *result = do_getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
+		result = do_getenv("TMP");
 		if (!result)
-			result = getenv("TEMP");
+			result = do_getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */
@@ -1019,9 +1045,6 @@ static wchar_t *make_environment_block(char **deltaenv)
 	for (i = 0; deltaenv && deltaenv[i]; i++)
 		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
-	/* environment must be sorted */
-	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
-
 	/* create environment block from temporary environment */
 	for (i = 0; tmpenv[i]; i++) {
 		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
@@ -2079,6 +2102,9 @@ void mingw_startup()
 	environ[i] = NULL;
 	free(buffer);
 
+	/* sort environment for O(log n) getenv / putenv */
+	qsort(environ, i, sizeof(char*), compareenv);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 1ec4c0695f56574abaa0305bdaddb50e149fec72 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:35:26 +0100
Subject: [PATCH 3010/3720] Win32: patch Windows environment on startup

Fix Windows specific environment settings on startup rather than checking
for special values on every getenv call.

As a side effect, this makes the patched environment (i.e. with properly
initialized TMPDIR and TERM) available to child processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index b569faf0b0..183a2a4558 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -809,7 +809,7 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-static char *do_getenv(const char *name)
+char *mingw_getenv(const char *name)
 {
 	char *value;
 	int pos = bsearchenv(environ, name, environ_size - 1);
@@ -819,22 +819,6 @@ static char *do_getenv(const char *name)
 	return value ? &value[1] : NULL;
 }
 
-char *mingw_getenv(const char *name)
-{
-	char *result = do_getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = do_getenv("TMP");
-		if (!result)
-			result = do_getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 int mingw_putenv(const char *namevalue)
 {
 	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
@@ -2105,6 +2089,21 @@ void mingw_startup()
 	/* sort environment for O(log n) getenv / putenv */
 	qsort(environ, i, sizeof(char*), compareenv);
 
+	/* fix Windows specific environment settings */
+
+	/* on Windows it is TMP and TEMP */
+	if (!getenv("TMPDIR")) {
+		const char *tmp = getenv("TMP");
+		if (!tmp)
+			tmp = getenv("TEMP");
+		if (tmp)
+			setenv("TMPDIR", tmp, 1);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "winansi", 1);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 36f44d8ceaa608b25997a18cb77513e6827f910c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 14 Feb 2012 14:13:19 -0600
Subject: [PATCH 3011/3720] fixup! grep -I: do not bother to read known-binary
 files

---
 builtin/grep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index e1817e45c0..4f4dc26b3e 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -189,7 +189,7 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
-		if (skip_binary(opt, (const char *)w->identifier))
+		if (skip_binary(opt, (const char *)w->source.identifier))
 			continue;
 
 		opt->output_priv = w;

From 4da60d350ede8ce60f1a4edc8058a2c15ba71427 Mon Sep 17 00:00:00 2001
From: Luke Diamand 
Date: Tue, 14 Feb 2012 22:33:55 +0000
Subject: [PATCH 3012/3720] git-p4: add initial support for RCS keywords

RCS keywords cause problems for git-p4 as perforce always
expands them (if +k is set) and so when applying the patch,
git reports that the files have been modified by both sides,
when in fact they haven't.

This change means that when git-p4 detects a problem applying
a patch, it will check to see if keyword expansion could be
the culprit. If it is, it strips the keywords in the p4
repository so that they match what git is expecting. It then
has another go at applying the patch.

This behaviour is enabled with a new git-p4 configuration
option and is off by default.

Improved-by: Pete Wyckoff 
Signed-off-by: Luke Diamand 
Signed-off-by: Junio C Hamano 
---
 Documentation/git-p4.txt   |   5 +
 contrib/fast-import/git-p4 | 116 ++++++++++++--
 t/t9810-git-p4-rcs.sh      | 304 +++++++++++++++++++++++++++++++++++++
 3 files changed, 415 insertions(+), 10 deletions(-)
 create mode 100755 t/t9810-git-p4-rcs.sh

diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index 8b92cc0f8d..7fa47c83ba 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -483,6 +483,11 @@ git-p4.skipUserNameCheck::
 	user map, 'git p4' exits.  This option can be used to force
 	submission regardless.
 
+git-p4.attemptRCSCleanup:
+    If enabled, 'git p4 submit' will attempt to sort cleanup RCS keywords
+    ($Header$, etc). These would otherwise cause merge conflicts and prevent
+    the submit going ahead. This option should be considered experimental at
+    present.
 
 IMPLEMENTATION DETAILS
 ----------------------
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index a78d9c5493..8130447edf 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -10,7 +10,7 @@
 
 import optparse, sys, os, marshal, subprocess, shelve
 import tempfile, getopt, os.path, time, platform
-import re
+import re, shutil
 
 verbose = False
 
@@ -186,6 +186,44 @@ def split_p4_type(p4type):
         mods = s[1]
     return (base, mods)
 
+#
+# return the raw p4 type of a file (text, text+ko, etc)
+#
+def p4_type(file):
+    files = p4_read_pipe_lines(["files", file])
+    info = files[0]
+    m = re.search(r'\(([a-z0-9A-Z+]+)\)\s*$', info)
+    if m:
+        ret = m.group(1)
+        if verbose:
+            print "%s => %s" % (file, ret)
+        return ret
+    else:
+        die("Could not extract file type from '%s'" % info)
+
+#
+# Given a type base and modifier, return a regexp matching
+# the keywords that can be expanded in the file
+#
+def p4_keywords_regexp_for_type(base, type_mods):
+    if base in ("text", "unicode", "binary"):
+        if "ko" in type_mods:
+            return r'\$(Id|Header)[^$]*\$'
+        elif "k" in type_mods:
+            return r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision)[^$]*\$'
+        else:
+            return None
+    else:
+        return None
+
+#
+# Given a file, return a regexp matching the possible
+# RCS keywords that will be expanded, or None for files
+# with kw expansion turned off.
+#
+def p4_keywords_regexp_for_file(file):
+    (type_base, type_mods) = split_p4_type(p4_type(file))
+    return p4_keywords_regexp_for_type(type_base, type_mods)
 
 def setP4ExecBit(file, mode):
     # Reopens an already open file and changes the execute bit to match
@@ -753,6 +791,28 @@ class P4Submit(Command, P4UserMap):
 
         return result
 
+    def patchRCSKeywords(self, file, pattern):
+        # Attempt to zap the RCS keywords in a p4 controlled file matching the given pattern
+        (handle, outFileName) = tempfile.mkstemp(dir='.')
+        try:
+            outFile = os.fdopen(handle, "w+")
+            inFile = open(file, "r")
+            for line in inFile.readlines():
+                line = re.sub(pattern, r'$\1$', line)
+                outFile.write(line)
+            inFile.close()
+            outFile.close()
+            # Forcibly overwrite the original file
+            os.unlink(file)
+            shutil.move(outFileName, file)
+        except:
+            # cleanup our temporary file
+            os.unlink(outFileName)
+            print "Failed to strip RCS keywords in %s" % file
+            raise
+
+        print "Patched up RCS keywords in %s" % file
+
     def p4UserForCommit(self,id):
         # Return the tuple (perforce user,git email) for a given git commit id
         self.getUserMapFromPerforceServer()
@@ -918,6 +978,7 @@ class P4Submit(Command, P4UserMap):
         filesToDelete = set()
         editedFiles = set()
         filesToChangeExecBit = {}
+
         for line in diff:
             diff = parseDiffTreeEntry(line)
             modifier = diff['status']
@@ -964,9 +1025,48 @@ class P4Submit(Command, P4UserMap):
         patchcmd = diffcmd + " | git apply "
         tryPatchCmd = patchcmd + "--check -"
         applyPatchCmd = patchcmd + "--check --apply -"
+        patch_succeeded = True
 
         if os.system(tryPatchCmd) != 0:
+            fixed_rcs_keywords = False
+            patch_succeeded = False
             print "Unfortunately applying the change failed!"
+
+            # Patch failed, maybe it's just RCS keyword woes. Look through
+            # the patch to see if that's possible.
+            if gitConfig("git-p4.attemptRCSCleanup","--bool") == "true":
+                file = None
+                pattern = None
+                kwfiles = {}
+                for line in read_pipe_lines(diffcmd):
+                    # read diff lines: for each file reported, if it can have
+                    # keywords expanded, and the diff contains keywords, then
+                    # try zapping the p4 file.
+                    m = re.match(r'^diff --git a/(.*)\s+b/(.*)', line)
+                    if m:
+                        file = m.group(1)
+                        pattern = p4_keywords_regexp_for_file(file)
+                        next
+
+                    if pattern:
+                        print line
+
+                    if pattern and re.search(pattern, line):
+                        print "got match on %s in %s in %s" % (pattern, line, file)
+                        kwfiles[file] = pattern
+
+                for file in kwfiles:
+                    if verbose:
+                        print "zapping %s with %s" % (line,pattern)
+                    self.patchRCSKeywords(file, kwfiles[file])
+                    fixed_rcs_keywords = True
+
+            if fixed_rcs_keywords:
+                print "Retrying the patch with RCS keywords cleaned up"
+                if os.system(tryPatchCmd) == 0:
+                    patch_succeeded = True
+
+        if not patch_succeeded:
             print "What do you want to do?"
             response = "x"
             while response != "s" and response != "a" and response != "w":
@@ -1585,15 +1685,11 @@ class P4Sync(Command, P4UserMap):
 
         # Note that we do not try to de-mangle keywords on utf16 files,
         # even though in theory somebody may want that.
-        if type_base in ("text", "unicode", "binary"):
-            if "ko" in type_mods:
-                text = ''.join(contents)
-                text = re.sub(r'\$(Id|Header):[^$]*\$', r'$\1$', text)
-                contents = [ text ]
-            elif "k" in type_mods:
-                text = ''.join(contents)
-                text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', text)
-                contents = [ text ]
+        pattern = p4_keywords_regexp_for_type(type_base, type_mods)
+        if pattern:
+            text = ''.join(contents)
+            text = re.sub(pattern, r'$\1$', text)
+            contents = [ text ]
 
         self.gitStream.write("M %s inline %s\n" % (git_mode, relPath))
 
diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh
new file mode 100755
index 0000000000..3013babf55
--- /dev/null
+++ b/t/t9810-git-p4-rcs.sh
@@ -0,0 +1,304 @@
+#!/bin/sh
+
+test_description='git-p4 rcs keywords'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+	start_p4d
+'
+
+#
+# Make one file with keyword lines at the top, and
+# enough plain text to be able to test modifications
+# far away from the keywords.
+#
+test_expect_success 'init depot' '
+	(
+		cd "$cli" &&
+		cat <<-\EOF >filek &&
+		$Id$
+		/* $Revision$ */
+		# $Change$
+		line4
+		line5
+		line6
+		line7
+		line8
+		EOF
+		cp filek fileko &&
+		sed -i "s/Revision/Revision: do not scrub me/" fileko
+		cp fileko file_text &&
+		sed -i "s/Id/Id: do not scrub me/" file_text
+		p4 add -t text+k filek &&
+		p4 submit -d "filek" &&
+		p4 add -t text+ko fileko &&
+		p4 submit -d "fileko" &&
+		p4 add -t text file_text &&
+		p4 submit -d "file_text"
+	)
+'
+
+#
+# Generate these in a function to make it easy to use single quote marks.
+#
+write_scrub_scripts() {
+	cat >"$TRASH_DIRECTORY/scrub_k.py" <<-\EOF &&
+	import re, sys
+	sys.stdout.write(re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', sys.stdin.read()))
+	EOF
+	cat >"$TRASH_DIRECTORY/scrub_ko.py" <<-\EOF
+	import re, sys
+	sys.stdout.write(re.sub(r'(?i)\$(Id|Header):[^$]*\$', r'$\1$', sys.stdin.read()))
+	EOF
+}
+
+test_expect_success 'scrub scripts' '
+	write_scrub_scripts
+'
+
+#
+# Compare $cli/file to its scrubbed version, should be different.
+# Compare scrubbed $cli/file to $git/file, should be same.
+#
+scrub_k_check() {
+	file=$1 &&
+	scrub="$TRASH_DIRECTORY/$file" &&
+	"$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_k.py" <"$git/$file" >"$scrub" &&
+	! test_cmp "$cli/$file" "$scrub" &&
+	test_cmp "$git/$file" "$scrub" &&
+	rm "$scrub"
+}
+scrub_ko_check() {
+	file=$1 &&
+	scrub="$TRASH_DIRECTORY/$file" &&
+	"$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_ko.py" <"$git/$file" >"$scrub" &&
+	! test_cmp "$cli/$file" "$scrub" &&
+	test_cmp "$git/$file" "$scrub" &&
+	rm "$scrub"
+}
+
+#
+# Modify far away from keywords.  If no RCS lines show up
+# in the diff, there is no conflict.
+#
+test_expect_success 'edit far away from RCS lines' '
+	test_when_finished cleanup_git &&
+	"$GITP4" clone --dest="$git" //depot &&
+	(
+		cd "$git" &&
+		git config git-p4.skipSubmitEdit true &&
+		sed -i "s/^line7/line7 edit/" filek &&
+		git commit -m "filek line7 edit" filek &&
+		"$GITP4" submit &&
+		scrub_k_check filek
+	)
+'
+
+#
+# Modify near the keywords.  This will require RCS scrubbing.
+#
+test_expect_success 'edit near RCS lines' '
+	test_when_finished cleanup_git &&
+	"$GITP4" clone --dest="$git" //depot &&
+	(
+		cd "$git" &&
+		git config git-p4.skipSubmitEdit true &&
+		git config git-p4.attemptRCSCleanup true &&
+		sed -i "s/^line4/line4 edit/" filek &&
+		git commit -m "filek line4 edit" filek &&
+		"$GITP4" submit &&
+		scrub_k_check filek
+	)
+'
+
+#
+# Modify the keywords themselves.  This also will require RCS scrubbing.
+#
+test_expect_success 'edit keyword lines' '
+	test_when_finished cleanup_git &&
+	"$GITP4" clone --dest="$git" //depot &&
+	(
+		cd "$git" &&
+		git config git-p4.skipSubmitEdit true &&
+		git config git-p4.attemptRCSCleanup true &&
+		sed -i "/Revision/d" filek &&
+		git commit -m "filek remove Revision line" filek &&
+		"$GITP4" submit &&
+		scrub_k_check filek
+	)
+'
+
+#
+# Scrubbing text+ko files should not alter all keywords, just Id, Header.
+#
+test_expect_success 'scrub ko files differently' '
+	test_when_finished cleanup_git &&
+	"$GITP4" clone --dest="$git" //depot &&
+	(
+		cd "$git" &&
+		git config git-p4.skipSubmitEdit true &&
+		git config git-p4.attemptRCSCleanup true &&
+		sed -i "s/^line4/line4 edit/" fileko &&
+		git commit -m "fileko line4 edit" fileko &&
+		"$GITP4" submit &&
+		scrub_ko_check fileko &&
+		! scrub_k_check fileko
+	)
+'
+
+# hack; git-p4 submit should do it on its own
+test_expect_success 'cleanup after failure' '
+	(
+		cd "$cli" &&
+		p4 revert ...
+	)
+'
+
+#
+# Do not scrub anything but +k or +ko files.  Sneak a change into
+# the cli file so that submit will get a conflict.  Make sure that
+# scrubbing doesn't make a mess of things.
+#
+# Assumes that git-p4 exits leaving the p4 file open, with the
+# conflict-generating patch unapplied.
+#
+# This might happen only if the git repo is behind the p4 repo at
+# submit time, and there is a conflict.
+#
+test_expect_success 'do not scrub plain text' '
+	test_when_finished cleanup_git &&
+	"$GITP4" clone --dest="$git" //depot &&
+	(
+		cd "$git" &&
+		git config git-p4.skipSubmitEdit true &&
+		git config git-p4.attemptRCSCleanup true &&
+		sed -i "s/^line4/line4 edit/" file_text &&
+		git commit -m "file_text line4 edit" file_text &&
+		(
+			cd "$cli" &&
+			p4 open file_text &&
+			sed -i "s/^line5/line5 p4 edit/" file_text &&
+			p4 submit -d "file5 p4 edit"
+		) &&
+		! "$GITP4" submit &&
+		(
+			# exepct something like:
+			#    file_text - file(s) not opened on this client
+			# but not copious diff output
+			cd "$cli" &&
+			p4 diff file_text >wc &&
+			test_line_count = 1 wc
+		)
+	)
+'
+
+# hack; git-p4 submit should do it on its own
+test_expect_success 'cleanup after failure 2' '
+	(
+		cd "$cli" &&
+		p4 revert ...
+	)
+'
+
+create_kw_file () {
+	cat <<\EOF >"$1"
+/* A file
+	Id: $Id$
+	Revision: $Revision$
+	File: $File$
+ */
+int main(int argc, const char **argv) {
+	return 0;
+}
+EOF
+}
+
+test_expect_success 'add kwfile' '
+	(
+		cd "$cli" &&
+		echo file1 >file1 &&
+		p4 add file1 &&
+		p4 submit -d "file 1" &&
+		create_kw_file kwfile1.c &&
+		p4 add kwfile1.c &&
+		p4 submit -d "Add rcw kw file" kwfile1.c
+	)
+'
+
+p4_append_to_file () {
+	f=$1 &&
+	p4 edit -t ktext "$f" &&
+	echo "/* $(date) */" >>"$f" &&
+	p4 submit -d "appending a line in p4"
+}
+
+# Create some files with RCS keywords. If they get modified
+# elsewhere then the version number gets bumped which then
+# results in a merge conflict if we touch the RCS kw lines,
+# even though the change itself would otherwise apply cleanly.
+test_expect_success 'cope with rcs keyword expansion damage' '
+	test_when_finished cleanup_git &&
+	"$GITP4" clone --dest="$git" //depot &&
+	(
+		cd "$git" &&
+		git config git-p4.skipSubmitEdit true &&
+		git config git-p4.attemptRCSCleanup true &&
+		(cd ../cli && p4_append_to_file kwfile1.c) &&
+		old_lines=$(wc -l >kwfile1.c &&
+		p4 submit -d "add a line in p4" kwfile1.c &&
+		cd "$git" &&
+		echo "line from git at the top" | cat - kwfile1.c >kwfile1.c.new &&
+		mv kwfile1.c.new kwfile1.c &&
+		git commit -m "Add line in git at the top" kwfile1.c &&
+		"$GITP4" rebase &&
+		"$GITP4" submit
+	)
+'
+
+test_expect_success 'cope with rcs keyword file deletion' '
+	test_when_finished cleanup_git &&
+	(
+		cd "$cli" &&
+		echo "\$Revision\$" >kwdelfile.c &&
+		p4 add -t ktext kwdelfile.c &&
+		p4 submit -d "Add file to be deleted" &&
+		cat kwdelfile.c &&
+		grep 1 kwdelfile.c
+	) &&
+	"$GITP4" clone --dest="$git" //depot &&
+	(
+		cd "$git" &&
+		grep Revision kwdelfile.c &&
+		git rm -f kwdelfile.c &&
+		git commit -m "Delete a file containing RCS keywords" &&
+		git config git-p4.skipSubmitEdit true &&
+		git config git-p4.attemptRCSCleanup true &&
+		"$GITP4" submit
+	) &&
+	(
+		cd "$cli" &&
+		p4 sync &&
+		[ ! -f kwdelfile.c ]
+	)
+'
+
+test_expect_success 'kill p4d' '
+	kill_p4d
+'
+
+test_done

From 8c9f1caf12cf5e4bf7c997faffd3c0df4f57749c Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Thu, 16 Feb 2012 11:27:29 -0800
Subject: [PATCH 3013/3720] Revert "config: add include directive"

This reverts commit 5d22f812d426103a29dcce50db47e5274ebaf67b; making it
simpler to queue the re-rolled series.
---
 Documentation/config.txt               |  15 ---
 Documentation/git-config.txt           |   5 -
 Documentation/technical/api-config.txt |  22 -----
 builtin/config.c                       |  31 ++----
 cache.h                                |   8 --
 config.c                               |  69 +-------------
 t/t1305-config-include.sh              | 126 -------------------------
 7 files changed, 8 insertions(+), 268 deletions(-)
 delete mode 100755 t/t1305-config-include.sh

diff --git a/Documentation/config.txt b/Documentation/config.txt
index e55dae1806..abeb82b2c6 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -84,17 +84,6 @@ customary UNIX fashion.
 
 Some variables may require a special value format.
 
-Includes
-~~~~~~~~
-
-You can include one config file from another by setting the special
-`include.path` variable to the name of the file to be included. The
-included file is expanded immediately, as if its contents had been
-found at the location of the include directive. If the value of the
-`include.path` variable is a relative path, the path is considered to be
-relative to the configuration file in which the include directive was
-found. See below for examples.
-
 Example
 ~~~~~~~
 
@@ -117,10 +106,6 @@ Example
 		gitProxy="ssh" for "kernel.org"
 		gitProxy=default-proxy ; for the rest
 
-	[include]
-		path = /path/to/foo.inc ; include by absolute path
-		path = foo ; expand "foo" relative to the current file
-
 Variables
 ~~~~~~~~~
 
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index aa8303b1ad..e7ecf5d803 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -178,11 +178,6 @@ See also <>.
 	Opens an editor to modify the specified config file; either
 	'--system', '--global', or repository (default).
 
---includes::
---no-includes::
-	Respect `include.*` directives in config files when looking up
-	values. Defaults to on.
-
 [[FILES]]
 FILES
 -----
diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
index c60b6b3c93..f428c5c486 100644
--- a/Documentation/technical/api-config.txt
+++ b/Documentation/technical/api-config.txt
@@ -95,28 +95,6 @@ string is given, prints an error message and returns -1.
 Similar to `git_config_string`, but expands `~` or `~user` into the
 user's home directory when found at the beginning of the path.
 
-Include Directives
-------------------
-
-By default, the config parser does not respect include directives.
-However, a caller can use the special `git_config_include` wrapper
-callback to support them. To do so, you simply wrap your "real" callback
-function and data pointer in a `struct config_include_data`, and pass
-the wrapper to the regular config-reading functions. For example:
-
--------------------------------------------
-int read_file_with_include(const char *file, config_fn_t fn, void *data)
-{
-	struct config_include_data inc = CONFIG_INCLUDE_INIT;
-	inc.fn = fn;
-	inc.data = data;
-	return git_config_from_file(git_config_include, file, &inc);
-}
--------------------------------------------
-
-`git_config` respects includes automatically. The lower-level
-`git_config_from_file` does not.
-
 Writing Config Files
 --------------------
 
diff --git a/builtin/config.c b/builtin/config.c
index 09bf778168..d35c06ae51 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -25,7 +25,6 @@ static const char *given_config_file;
 static int actions, types;
 static const char *get_color_slot, *get_colorbool_slot;
 static int end_null;
-static int respect_includes = -1;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -75,7 +74,6 @@ static struct option builtin_config_options[] = {
 	OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH),
 	OPT_GROUP("Other"),
 	OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
-	OPT_BOOL(0, "includes", &respect_includes, "respect include directives on lookup"),
 	OPT_END(),
 };
 
@@ -163,9 +161,6 @@ static int get_value(const char *key_, const char *regex_)
 	int ret = -1;
 	char *global = NULL, *repo_config = NULL;
 	const char *system_wide = NULL, *local;
-	struct config_include_data inc = CONFIG_INCLUDE_INIT;
-	config_fn_t fn;
-	void *data;
 
 	local = config_exclusive_filename;
 	if (!local) {
@@ -218,28 +213,19 @@ static int get_value(const char *key_, const char *regex_)
 		}
 	}
 
-	fn = show_config;
-	data = NULL;
-	if (respect_includes) {
-		inc.fn = fn;
-		inc.data = data;
-		fn = git_config_include;
-		data = &inc;
-	}
-
 	if (do_all && system_wide)
-		git_config_from_file(fn, system_wide, data);
+		git_config_from_file(show_config, system_wide, NULL);
 	if (do_all && global)
-		git_config_from_file(fn, global, data);
+		git_config_from_file(show_config, global, NULL);
 	if (do_all)
-		git_config_from_file(fn, local, data);
-	git_config_from_parameters(fn, data);
+		git_config_from_file(show_config, local, NULL);
+	git_config_from_parameters(show_config, NULL);
 	if (!do_all && !seen)
-		git_config_from_file(fn, local, data);
+		git_config_from_file(show_config, local, NULL);
 	if (!do_all && !seen && global)
-		git_config_from_file(fn, global, data);
+		git_config_from_file(show_config, global, NULL);
 	if (!do_all && !seen && system_wide)
-		git_config_from_file(fn, system_wide, data);
+		git_config_from_file(show_config, system_wide, NULL);
 
 	free(key);
 	if (regexp) {
@@ -398,9 +384,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			config_exclusive_filename = given_config_file;
 	}
 
-	if (respect_includes == -1)
-		respect_includes = !config_exclusive_filename;
-
 	if (end_null) {
 		term = '\0';
 		delim = '\n';
diff --git a/cache.h b/cache.h
index 94f3eaf603..ae0396b84d 100644
--- a/cache.h
+++ b/cache.h
@@ -1140,14 +1140,6 @@ extern const char *get_commit_output_encoding(void);
 
 extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-struct config_include_data {
-	int depth;
-	config_fn_t fn;
-	void *data;
-};
-#define CONFIG_INCLUDE_INIT { 0 }
-extern int git_config_include(const char *name, const char *value, void *data);
-
 extern const char *config_exclusive_filename;
 
 #define MAX_GITNAME (1000)
diff --git a/config.c b/config.c
index e3fcf7553c..40f9c6d103 100644
--- a/config.c
+++ b/config.c
@@ -28,69 +28,6 @@ static int zlib_compression_seen;
 
 const char *config_exclusive_filename = NULL;
 
-#define MAX_INCLUDE_DEPTH 10
-static const char include_depth_advice[] =
-"exceeded maximum include depth (%d) while including\n"
-"	%s\n"
-"from\n"
-"	%s\n"
-"Do you have circular includes?";
-static int handle_path_include(const char *path, struct config_include_data *inc)
-{
-	int ret = 0;
-	struct strbuf buf = STRBUF_INIT;
-
-	/*
-	 * Use an absolute path as-is, but interpret relative paths
-	 * based on the including config file.
-	 */
-	if (!is_absolute_path(path)) {
-		char *slash;
-
-		if (!cf || !cf->name)
-			return error("relative config includes must come from files");
-
-		slash = find_last_dir_sep(cf->name);
-		if (slash)
-			strbuf_add(&buf, cf->name, slash - cf->name + 1);
-		strbuf_addstr(&buf, path);
-		path = buf.buf;
-	}
-
-	if (!access(path, R_OK)) {
-		if (++inc->depth > MAX_INCLUDE_DEPTH)
-			die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
-			    cf && cf->name ? cf->name : "the command line");
-		ret = git_config_from_file(git_config_include, path, inc);
-		inc->depth--;
-	}
-	strbuf_release(&buf);
-	return ret;
-}
-
-int git_config_include(const char *var, const char *value, void *data)
-{
-	struct config_include_data *inc = data;
-	const char *type;
-	int ret;
-
-	/*
-	 * Pass along all values, including "include" directives; this makes it
-	 * possible to query information on the includes themselves.
-	 */
-	ret = inc->fn(var, value, inc->data);
-	if (ret < 0)
-		return ret;
-
-	type = skip_prefix(var, "include.");
-	if (!type)
-		return ret;
-
-	if (!strcmp(type, "path"))
-		ret = handle_path_include(value, inc);
-	return ret;
-}
-
 static void lowercase(char *p)
 {
 	for (; *p; p++)
@@ -984,13 +921,9 @@ int git_config(config_fn_t fn, void *data)
 {
 	char *repo_config = NULL;
 	int ret;
-	struct config_include_data inc = CONFIG_INCLUDE_INIT;
-
-	inc.fn = fn;
-	inc.data = data;
 
 	repo_config = git_pathdup("config");
-	ret = git_config_early(git_config_include, &inc, repo_config);
+	ret = git_config_early(fn, data, repo_config);
 	if (repo_config)
 		free(repo_config);
 	return ret;
diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh
deleted file mode 100755
index 0a27ec48d0..0000000000
--- a/t/t1305-config-include.sh
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/bin/sh
-
-test_description='test config file include directives'
-. ./test-lib.sh
-
-test_expect_success 'include file by absolute path' '
-	echo "[test]one = 1" >one &&
-	echo "[include]path = \"$PWD/one\"" >.gitconfig &&
-	echo 1 >expect &&
-	git config test.one >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'include file by relative path' '
-	echo "[test]one = 1" >one &&
-	echo "[include]path = one" >.gitconfig &&
-	echo 1 >expect &&
-	git config test.one >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'chained relative paths' '
-	mkdir subdir &&
-	echo "[test]three = 3" >subdir/three &&
-	echo "[include]path = three" >subdir/two &&
-	echo "[include]path = subdir/two" >.gitconfig &&
-	echo 3 >expect &&
-	git config test.three >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'include options can still be examined' '
-	echo "[test]one = 1" >one &&
-	echo "[include]path = one" >.gitconfig &&
-	echo one >expect &&
-	git config include.path >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'listing includes option and expansion' '
-	echo "[test]one = 1" >one &&
-	echo "[include]path = one" >.gitconfig &&
-	cat >expect <<-\EOF &&
-	include.path=one
-	test.one=1
-	EOF
-	git config --list >actual.full &&
-	grep -v ^core actual.full >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'single file lookup does not expand includes by default' '
-	echo "[test]one = 1" >one &&
-	echo "[include]path = one" >.gitconfig &&
-	test_must_fail git config -f .gitconfig test.one &&
-	test_must_fail git config --global test.one &&
-	echo 1 >expect &&
-	git config --includes -f .gitconfig test.one >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'writing config file does not expand includes' '
-	echo "[test]one = 1" >one &&
-	echo "[include]path = one" >.gitconfig &&
-	git config test.two 2 &&
-	echo 2 >expect &&
-	git config --no-includes test.two >actual &&
-	test_cmp expect actual &&
-	test_must_fail git config --no-includes test.one
-'
-
-test_expect_success 'config modification does not affect includes' '
-	echo "[test]one = 1" >one &&
-	echo "[include]path = one" >.gitconfig &&
-	git config test.one 2 &&
-	echo 1 >expect &&
-	git config -f one test.one >actual &&
-	test_cmp expect actual &&
-	cat >expect <<-\EOF &&
-	1
-	2
-	EOF
-	git config --get-all test.one >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'missing include files are ignored' '
-	cat >.gitconfig <<-\EOF &&
-	[include]path = foo
-	[test]value = yes
-	EOF
-	echo yes >expect &&
-	git config test.value >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'absolute includes from command line work' '
-	echo "[test]one = 1" >one &&
-	echo 1 >expect &&
-	git -c include.path="$PWD/one" config test.one >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'relative includes from command line fail' '
-	echo "[test]one = 1" >one &&
-	test_must_fail git -c include.path=one config test.one
-'
-
-test_expect_success 'include cycles are detected' '
-	cat >.gitconfig <<-\EOF &&
-	[test]value = gitconfig
-	[include]path = cycle
-	EOF
-	cat >cycle <<-\EOF &&
-	[test]value = cycle
-	[include]path = .gitconfig
-	EOF
-	cat >expect <<-\EOF &&
-	gitconfig
-	cycle
-	EOF
-	test_must_fail git config --get-all test.value 2>stderr &&
-	grep "exceeded maximum include depth" stderr
-'
-
-test_done

From 983da89ab0c7e6c887cf849c99831310a46e3633 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Thu, 23 Feb 2012 09:24:54 -0800
Subject: [PATCH 3014/3720] Revert "git-p4: add initial support for RCS
 keywords"

This reverts commit 4da60d350ede8ce60f1a4edc8058a2c15ba71427, to replace
it with a re-roll.
---
 Documentation/git-p4.txt   |   5 -
 contrib/fast-import/git-p4 | 116 ++------------
 t/t9810-git-p4-rcs.sh      | 304 -------------------------------------
 3 files changed, 10 insertions(+), 415 deletions(-)
 delete mode 100755 t/t9810-git-p4-rcs.sh

diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index 7fa47c83ba..8b92cc0f8d 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -483,11 +483,6 @@ git-p4.skipUserNameCheck::
 	user map, 'git p4' exits.  This option can be used to force
 	submission regardless.
 
-git-p4.attemptRCSCleanup:
-    If enabled, 'git p4 submit' will attempt to sort cleanup RCS keywords
-    ($Header$, etc). These would otherwise cause merge conflicts and prevent
-    the submit going ahead. This option should be considered experimental at
-    present.
 
 IMPLEMENTATION DETAILS
 ----------------------
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 914e547a99..d2fd265b1c 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -10,7 +10,7 @@
 
 import optparse, sys, os, marshal, subprocess, shelve
 import tempfile, getopt, os.path, time, platform
-import re, shutil
+import re
 
 verbose = False
 
@@ -186,44 +186,6 @@ def split_p4_type(p4type):
         mods = s[1]
     return (base, mods)
 
-#
-# return the raw p4 type of a file (text, text+ko, etc)
-#
-def p4_type(file):
-    files = p4_read_pipe_lines(["files", file])
-    info = files[0]
-    m = re.search(r'\(([a-z0-9A-Z+]+)\)\s*$', info)
-    if m:
-        ret = m.group(1)
-        if verbose:
-            print "%s => %s" % (file, ret)
-        return ret
-    else:
-        die("Could not extract file type from '%s'" % info)
-
-#
-# Given a type base and modifier, return a regexp matching
-# the keywords that can be expanded in the file
-#
-def p4_keywords_regexp_for_type(base, type_mods):
-    if base in ("text", "unicode", "binary"):
-        if "ko" in type_mods:
-            return r'\$(Id|Header)[^$]*\$'
-        elif "k" in type_mods:
-            return r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision)[^$]*\$'
-        else:
-            return None
-    else:
-        return None
-
-#
-# Given a file, return a regexp matching the possible
-# RCS keywords that will be expanded, or None for files
-# with kw expansion turned off.
-#
-def p4_keywords_regexp_for_file(file):
-    (type_base, type_mods) = split_p4_type(p4_type(file))
-    return p4_keywords_regexp_for_type(type_base, type_mods)
 
 def setP4ExecBit(file, mode):
     # Reopens an already open file and changes the execute bit to match
@@ -791,28 +753,6 @@ class P4Submit(Command, P4UserMap):
 
         return result
 
-    def patchRCSKeywords(self, file, pattern):
-        # Attempt to zap the RCS keywords in a p4 controlled file matching the given pattern
-        (handle, outFileName) = tempfile.mkstemp(dir='.')
-        try:
-            outFile = os.fdopen(handle, "w+")
-            inFile = open(file, "r")
-            for line in inFile.readlines():
-                line = re.sub(pattern, r'$\1$', line)
-                outFile.write(line)
-            inFile.close()
-            outFile.close()
-            # Forcibly overwrite the original file
-            os.unlink(file)
-            shutil.move(outFileName, file)
-        except:
-            # cleanup our temporary file
-            os.unlink(outFileName)
-            print "Failed to strip RCS keywords in %s" % file
-            raise
-
-        print "Patched up RCS keywords in %s" % file
-
     def p4UserForCommit(self,id):
         # Return the tuple (perforce user,git email) for a given git commit id
         self.getUserMapFromPerforceServer()
@@ -978,7 +918,6 @@ class P4Submit(Command, P4UserMap):
         filesToDelete = set()
         editedFiles = set()
         filesToChangeExecBit = {}
-
         for line in diff:
             diff = parseDiffTreeEntry(line)
             modifier = diff['status']
@@ -1025,48 +964,9 @@ class P4Submit(Command, P4UserMap):
         patchcmd = diffcmd + " | git apply "
         tryPatchCmd = patchcmd + "--check -"
         applyPatchCmd = patchcmd + "--check --apply -"
-        patch_succeeded = True
 
         if os.system(tryPatchCmd) != 0:
-            fixed_rcs_keywords = False
-            patch_succeeded = False
             print "Unfortunately applying the change failed!"
-
-            # Patch failed, maybe it's just RCS keyword woes. Look through
-            # the patch to see if that's possible.
-            if gitConfig("git-p4.attemptRCSCleanup","--bool") == "true":
-                file = None
-                pattern = None
-                kwfiles = {}
-                for line in read_pipe_lines(diffcmd):
-                    # read diff lines: for each file reported, if it can have
-                    # keywords expanded, and the diff contains keywords, then
-                    # try zapping the p4 file.
-                    m = re.match(r'^diff --git a/(.*)\s+b/(.*)', line)
-                    if m:
-                        file = m.group(1)
-                        pattern = p4_keywords_regexp_for_file(file)
-                        next
-
-                    if pattern:
-                        print line
-
-                    if pattern and re.search(pattern, line):
-                        print "got match on %s in %s in %s" % (pattern, line, file)
-                        kwfiles[file] = pattern
-
-                for file in kwfiles:
-                    if verbose:
-                        print "zapping %s with %s" % (line,pattern)
-                    self.patchRCSKeywords(file, kwfiles[file])
-                    fixed_rcs_keywords = True
-
-            if fixed_rcs_keywords:
-                print "Retrying the patch with RCS keywords cleaned up"
-                if os.system(tryPatchCmd) == 0:
-                    patch_succeeded = True
-
-        if not patch_succeeded:
             print "What do you want to do?"
             response = "x"
             while response != "s" and response != "a" and response != "w":
@@ -1685,11 +1585,15 @@ class P4Sync(Command, P4UserMap):
 
         # Note that we do not try to de-mangle keywords on utf16 files,
         # even though in theory somebody may want that.
-        pattern = p4_keywords_regexp_for_type(type_base, type_mods)
-        if pattern:
-            text = ''.join(contents)
-            text = re.sub(pattern, r'$\1$', text)
-            contents = [ text ]
+        if type_base in ("text", "unicode", "binary"):
+            if "ko" in type_mods:
+                text = ''.join(contents)
+                text = re.sub(r'\$(Id|Header):[^$]*\$', r'$\1$', text)
+                contents = [ text ]
+            elif "k" in type_mods:
+                text = ''.join(contents)
+                text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', text)
+                contents = [ text ]
 
         self.gitStream.write("M %s inline %s\n" % (git_mode, relPath))
 
diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh
deleted file mode 100755
index 3013babf55..0000000000
--- a/t/t9810-git-p4-rcs.sh
+++ /dev/null
@@ -1,304 +0,0 @@
-#!/bin/sh
-
-test_description='git-p4 rcs keywords'
-
-. ./lib-git-p4.sh
-
-test_expect_success 'start p4d' '
-	start_p4d
-'
-
-#
-# Make one file with keyword lines at the top, and
-# enough plain text to be able to test modifications
-# far away from the keywords.
-#
-test_expect_success 'init depot' '
-	(
-		cd "$cli" &&
-		cat <<-\EOF >filek &&
-		$Id$
-		/* $Revision$ */
-		# $Change$
-		line4
-		line5
-		line6
-		line7
-		line8
-		EOF
-		cp filek fileko &&
-		sed -i "s/Revision/Revision: do not scrub me/" fileko
-		cp fileko file_text &&
-		sed -i "s/Id/Id: do not scrub me/" file_text
-		p4 add -t text+k filek &&
-		p4 submit -d "filek" &&
-		p4 add -t text+ko fileko &&
-		p4 submit -d "fileko" &&
-		p4 add -t text file_text &&
-		p4 submit -d "file_text"
-	)
-'
-
-#
-# Generate these in a function to make it easy to use single quote marks.
-#
-write_scrub_scripts() {
-	cat >"$TRASH_DIRECTORY/scrub_k.py" <<-\EOF &&
-	import re, sys
-	sys.stdout.write(re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', sys.stdin.read()))
-	EOF
-	cat >"$TRASH_DIRECTORY/scrub_ko.py" <<-\EOF
-	import re, sys
-	sys.stdout.write(re.sub(r'(?i)\$(Id|Header):[^$]*\$', r'$\1$', sys.stdin.read()))
-	EOF
-}
-
-test_expect_success 'scrub scripts' '
-	write_scrub_scripts
-'
-
-#
-# Compare $cli/file to its scrubbed version, should be different.
-# Compare scrubbed $cli/file to $git/file, should be same.
-#
-scrub_k_check() {
-	file=$1 &&
-	scrub="$TRASH_DIRECTORY/$file" &&
-	"$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_k.py" <"$git/$file" >"$scrub" &&
-	! test_cmp "$cli/$file" "$scrub" &&
-	test_cmp "$git/$file" "$scrub" &&
-	rm "$scrub"
-}
-scrub_ko_check() {
-	file=$1 &&
-	scrub="$TRASH_DIRECTORY/$file" &&
-	"$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_ko.py" <"$git/$file" >"$scrub" &&
-	! test_cmp "$cli/$file" "$scrub" &&
-	test_cmp "$git/$file" "$scrub" &&
-	rm "$scrub"
-}
-
-#
-# Modify far away from keywords.  If no RCS lines show up
-# in the diff, there is no conflict.
-#
-test_expect_success 'edit far away from RCS lines' '
-	test_when_finished cleanup_git &&
-	"$GITP4" clone --dest="$git" //depot &&
-	(
-		cd "$git" &&
-		git config git-p4.skipSubmitEdit true &&
-		sed -i "s/^line7/line7 edit/" filek &&
-		git commit -m "filek line7 edit" filek &&
-		"$GITP4" submit &&
-		scrub_k_check filek
-	)
-'
-
-#
-# Modify near the keywords.  This will require RCS scrubbing.
-#
-test_expect_success 'edit near RCS lines' '
-	test_when_finished cleanup_git &&
-	"$GITP4" clone --dest="$git" //depot &&
-	(
-		cd "$git" &&
-		git config git-p4.skipSubmitEdit true &&
-		git config git-p4.attemptRCSCleanup true &&
-		sed -i "s/^line4/line4 edit/" filek &&
-		git commit -m "filek line4 edit" filek &&
-		"$GITP4" submit &&
-		scrub_k_check filek
-	)
-'
-
-#
-# Modify the keywords themselves.  This also will require RCS scrubbing.
-#
-test_expect_success 'edit keyword lines' '
-	test_when_finished cleanup_git &&
-	"$GITP4" clone --dest="$git" //depot &&
-	(
-		cd "$git" &&
-		git config git-p4.skipSubmitEdit true &&
-		git config git-p4.attemptRCSCleanup true &&
-		sed -i "/Revision/d" filek &&
-		git commit -m "filek remove Revision line" filek &&
-		"$GITP4" submit &&
-		scrub_k_check filek
-	)
-'
-
-#
-# Scrubbing text+ko files should not alter all keywords, just Id, Header.
-#
-test_expect_success 'scrub ko files differently' '
-	test_when_finished cleanup_git &&
-	"$GITP4" clone --dest="$git" //depot &&
-	(
-		cd "$git" &&
-		git config git-p4.skipSubmitEdit true &&
-		git config git-p4.attemptRCSCleanup true &&
-		sed -i "s/^line4/line4 edit/" fileko &&
-		git commit -m "fileko line4 edit" fileko &&
-		"$GITP4" submit &&
-		scrub_ko_check fileko &&
-		! scrub_k_check fileko
-	)
-'
-
-# hack; git-p4 submit should do it on its own
-test_expect_success 'cleanup after failure' '
-	(
-		cd "$cli" &&
-		p4 revert ...
-	)
-'
-
-#
-# Do not scrub anything but +k or +ko files.  Sneak a change into
-# the cli file so that submit will get a conflict.  Make sure that
-# scrubbing doesn't make a mess of things.
-#
-# Assumes that git-p4 exits leaving the p4 file open, with the
-# conflict-generating patch unapplied.
-#
-# This might happen only if the git repo is behind the p4 repo at
-# submit time, and there is a conflict.
-#
-test_expect_success 'do not scrub plain text' '
-	test_when_finished cleanup_git &&
-	"$GITP4" clone --dest="$git" //depot &&
-	(
-		cd "$git" &&
-		git config git-p4.skipSubmitEdit true &&
-		git config git-p4.attemptRCSCleanup true &&
-		sed -i "s/^line4/line4 edit/" file_text &&
-		git commit -m "file_text line4 edit" file_text &&
-		(
-			cd "$cli" &&
-			p4 open file_text &&
-			sed -i "s/^line5/line5 p4 edit/" file_text &&
-			p4 submit -d "file5 p4 edit"
-		) &&
-		! "$GITP4" submit &&
-		(
-			# exepct something like:
-			#    file_text - file(s) not opened on this client
-			# but not copious diff output
-			cd "$cli" &&
-			p4 diff file_text >wc &&
-			test_line_count = 1 wc
-		)
-	)
-'
-
-# hack; git-p4 submit should do it on its own
-test_expect_success 'cleanup after failure 2' '
-	(
-		cd "$cli" &&
-		p4 revert ...
-	)
-'
-
-create_kw_file () {
-	cat <<\EOF >"$1"
-/* A file
-	Id: $Id$
-	Revision: $Revision$
-	File: $File$
- */
-int main(int argc, const char **argv) {
-	return 0;
-}
-EOF
-}
-
-test_expect_success 'add kwfile' '
-	(
-		cd "$cli" &&
-		echo file1 >file1 &&
-		p4 add file1 &&
-		p4 submit -d "file 1" &&
-		create_kw_file kwfile1.c &&
-		p4 add kwfile1.c &&
-		p4 submit -d "Add rcw kw file" kwfile1.c
-	)
-'
-
-p4_append_to_file () {
-	f=$1 &&
-	p4 edit -t ktext "$f" &&
-	echo "/* $(date) */" >>"$f" &&
-	p4 submit -d "appending a line in p4"
-}
-
-# Create some files with RCS keywords. If they get modified
-# elsewhere then the version number gets bumped which then
-# results in a merge conflict if we touch the RCS kw lines,
-# even though the change itself would otherwise apply cleanly.
-test_expect_success 'cope with rcs keyword expansion damage' '
-	test_when_finished cleanup_git &&
-	"$GITP4" clone --dest="$git" //depot &&
-	(
-		cd "$git" &&
-		git config git-p4.skipSubmitEdit true &&
-		git config git-p4.attemptRCSCleanup true &&
-		(cd ../cli && p4_append_to_file kwfile1.c) &&
-		old_lines=$(wc -l >kwfile1.c &&
-		p4 submit -d "add a line in p4" kwfile1.c &&
-		cd "$git" &&
-		echo "line from git at the top" | cat - kwfile1.c >kwfile1.c.new &&
-		mv kwfile1.c.new kwfile1.c &&
-		git commit -m "Add line in git at the top" kwfile1.c &&
-		"$GITP4" rebase &&
-		"$GITP4" submit
-	)
-'
-
-test_expect_success 'cope with rcs keyword file deletion' '
-	test_when_finished cleanup_git &&
-	(
-		cd "$cli" &&
-		echo "\$Revision\$" >kwdelfile.c &&
-		p4 add -t ktext kwdelfile.c &&
-		p4 submit -d "Add file to be deleted" &&
-		cat kwdelfile.c &&
-		grep 1 kwdelfile.c
-	) &&
-	"$GITP4" clone --dest="$git" //depot &&
-	(
-		cd "$git" &&
-		grep Revision kwdelfile.c &&
-		git rm -f kwdelfile.c &&
-		git commit -m "Delete a file containing RCS keywords" &&
-		git config git-p4.skipSubmitEdit true &&
-		git config git-p4.attemptRCSCleanup true &&
-		"$GITP4" submit
-	) &&
-	(
-		cd "$cli" &&
-		p4 sync &&
-		[ ! -f kwdelfile.c ]
-	)
-'
-
-test_expect_success 'kill p4d' '
-	kill_p4d
-'
-
-test_done

From 3e20962920dd17d6a20a3eb1350d60a8c54d80e6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 1 Mar 2012 21:53:54 +0100
Subject: [PATCH 3015/3720] Win32: fix broken pipe detection

As of "Win32: Thread-safe windows console output", git-log no longer
terminates when the pager process dies. This is due to disabling buffering
for the replaced stdout / stderr streams. Git-log will periodically fflush
stdout (see write_or_die.c/mayble_flush_or_die()), but with no buffering,
this is a NOP that always succeeds (so we never detect the EPIPE error).

Exchange the original console handles with our console thread pipe handles
by accessing the internal MSVCRT data structures directly (which are
exposed via __pioinfo for some reason).

Implement this with minimal assumptions about the actual data structure to
make it work with different (hopefully even future) MSVCRT versions.

While messing with internal data structures is ugly, this patch solves the
problem at the source instead of adding more workarounds. We no longer need
the special winansi_isatty override, and the limitations documented in
"Win32: Thread-safe windows console output" are gone (i.e. fdopen(1/2)
returns unbuffered streams now, and isatty() for duped console file
descriptors works as expected).

Signed-off-by: Karsten Blees 
---
 compat/mingw.h   |   2 -
 compat/winansi.c | 112 +++++++++++++++++++++++++++++------------------
 2 files changed, 69 insertions(+), 45 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 04b6523255..ad871772f7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -305,9 +305,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  */
 
 void winansi_init(void);
-int winansi_isatty(int fd);
 HANDLE winansi_get_osfhandle(int fd);
-#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index 9f95954390..040ef5adca 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -7,11 +7,6 @@
 #include 
 #include 
 
-/*
- Functions to be wrapped:
-*/
-#undef isatty
-
 /*
  ANSI codes used by git: m, K
 
@@ -103,6 +98,7 @@ static int is_console(int fd)
 
 	/* initialize attributes */
 	if (!initialized) {
+		console = hcon;
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
@@ -463,29 +459,80 @@ static HANDLE duplicate_handle(HANDLE hnd)
 	return hresult;
 }
 
-static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+
+/*
+ * Make MSVCRT's internal file descriptor control structure accessible
+ * so that we can tweak OS handles and flags directly (we need MSVCRT
+ * to treat our pipe handle as if it were a console).
+ *
+ * We assume that the ioinfo structure (exposed by MSVCRT.dll via
+ * __pioinfo) starts with the OS handle and the flags. The exact size
+ * varies between MSVCRT versions, so we try different sizes until
+ * toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
+ * isatty(1).
+ */
+typedef struct {
+	HANDLE osfhnd;
+	char osflags;
+} ioinfo;
+
+extern __declspec(dllimport) ioinfo *__pioinfo[];
+
+static size_t sizeof_ioinfo = 0;
+
+#define IOINFO_L2E 5
+#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
+
+#define FDEV  0x40
+
+static inline ioinfo* _pioinfo(int fd)
 {
-	/* get original console handle */
-	int fd = _fileno(stream);
-	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
-	if (hcon == INVALID_HANDLE_VALUE)
-		die_errno("_get_osfhandle(%i) failed", fd);
+	return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
+			(fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
+}
 
-	/* save a copy to phcon and console (used by the background thread) */
-	console = *phcon = duplicate_handle(hcon);
+static int init_sizeof_ioinfo()
+{
+	int istty, wastty;
+	/* don't init twice */
+	if (sizeof_ioinfo)
+		return sizeof_ioinfo >= 256;
 
-	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
-	if (_dup2(new_fd, fd))
-		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+	sizeof_ioinfo = sizeof(ioinfo);
+	wastty = isatty(1);
+	while (sizeof_ioinfo < 256) {
+		/* toggle FDEV flag, check isatty, then toggle back */
+		_pioinfo(1)->osflags ^= FDEV;
+		istty = isatty(1);
+		_pioinfo(1)->osflags ^= FDEV;
+		/* return if we found the correct size */
+		if (istty != wastty)
+			return 0;
+		sizeof_ioinfo += sizeof(void*);
+	}
+	error("Tweaking file descriptors doesn't work with this MSVCRT.dll");
+	return 1;
+}
 
-	/* no buffering, or stdout / stderr will be out of sync */
-	setbuf(stream, NULL);
-	return (HANDLE) _get_osfhandle(fd);
+static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
+{
+	ioinfo *pioinfo;
+	HANDLE old_handle;
+
+	/* init ioinfo size if we haven't done so */
+	if (init_sizeof_ioinfo())
+		return INVALID_HANDLE_VALUE;
+
+	/* get ioinfo pointer and change the handles */
+	pioinfo = _pioinfo(fd);
+	old_handle = pioinfo->osfhnd;
+	pioinfo->osfhnd = new_handle;
+	return old_handle;
 }
 
 void winansi_init(void)
 {
-	int con1, con2, hwrite_fd;
+	int con1, con2;
 	char name[32];
 
 	/* check if either stdout or stderr is a console output screen buffer */
@@ -514,19 +561,11 @@ void winansi_init(void)
 	if (atexit(winansi_exit))
 		die_errno("atexit(winansi_exit) failed");
 
-	/* create a file descriptor for the write end of the pipe */
-	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
-	if (hwrite_fd == -1)
-		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
-
 	/* redirect stdout / stderr to the pipe */
 	if (con1)
-		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+		hconsole1 = swap_osfhnd(1, hwrite1 = duplicate_handle(hwrite));
 	if (con2)
-		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
-
-	/* close pipe file descriptor (also closes the duped hwrite) */
-	close(hwrite_fd);
+		hconsole2 = swap_osfhnd(2, hwrite2 = duplicate_handle(hwrite));
 }
 
 static int is_same_handle(HANDLE hnd, int fd)
@@ -534,19 +573,6 @@ static int is_same_handle(HANDLE hnd, int fd)
 	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
 }
 
-/*
- * Return true if stdout / stderr is a pipe redirecting to the console.
- */
-int winansi_isatty(int fd)
-{
-	if (fd == 1 && is_same_handle(hwrite1, 1))
-		return 1;
-	else if (fd == 2 && is_same_handle(hwrite2, 2))
-		return 1;
-	else
-		return isatty(fd);
-}
-
 /*
  * Returns the real console handle if stdout / stderr is a pipe redirecting
  * to the console. Allows spawn / exec to pass the console to the next process.

From 3a2d620e5597ac2db16c034effe5173b7b119a2b Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Mon, 5 Mar 2012 10:52:11 -0800
Subject: [PATCH 3016/3720] fmt-merge-msg: show those involved in a merged
 series

As we already walk the history of the branch that gets merged to
come up with a short log, let's label it with names of the primary
authors, so that the user who summarizes the merge can easily give
credit to them in the log message.

Also infer the names of "lieutents" to help integrators at higher
level of the food-chain to give credit to them, by counting:

 * The committer of the 'tip' commit that is merged
 * The committer of merge commits that are merged

Often the first one gives the owner of the history being pulled, but
his last pull from his sublieutenants may have been a fast-forward,
in which case the first one would not be.  The latter rule will
count the integrator of the history, so together it might be a
reasonable heuristics.

Signed-off-by: Junio C Hamano 
---
 builtin/fmt-merge-msg.c         | 103 ++++++++++++++++++++++++++++++--
 t/t6200-fmt-merge-msg.sh        |  32 +++++++++-
 t/t7600-merge.sh                |   1 +
 t/t7604-merge-custom-message.sh |   1 +
 4 files changed, 130 insertions(+), 7 deletions(-)

diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index c81a7fef26..cbe32941ed 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -27,6 +27,8 @@ int fmt_merge_msg_config(const char *key, const char *value, void *cb)
 			merge_log_config = DEFAULT_MERGE_LOG_LEN;
 	} else if (!strcmp(key, "merge.branchdesc")) {
 		use_branch_desc = git_config_bool(key, value);
+	} else {
+		return git_default_config(key, value, cb);
 	}
 	return 0;
 }
@@ -180,6 +182,91 @@ static void add_branch_desc(struct strbuf *out, const char *name)
 	strbuf_release(&desc);
 }
 
+static void record_person(int which, struct string_list *people,
+			  struct commit *commit)
+{
+	char name_buf[MAX_GITNAME], *name, *name_end;
+	struct string_list_item *elem;
+	const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
+
+	name = strstr(commit->buffer, field);
+	if (!name)
+		return;
+	name += strlen(field);
+	name_end = strchrnul(name, '<');
+	if (*name_end)
+		name_end--;
+	while (isspace(*name_end) && name <= name_end)
+		name_end--;
+	if (name_end < name || name + MAX_GITNAME <= name_end)
+		return;
+	memcpy(name_buf, name, name_end - name + 1);
+	name_buf[name_end - name + 1] = '\0';
+
+	elem = string_list_lookup(people, name_buf);
+	if (!elem) {
+		elem = string_list_insert(people, name_buf);
+		elem->util = (void *) 0;
+	}
+	elem->util = (void*)(((intptr_t)elem->util) + 1);
+}
+
+#define util_as_int(elem) ((intptr_t)((elem)->util))
+
+static int cmp_string_list_util_as_int(const void *a_, const void *b_)
+{
+	const struct string_list_item *a = a_, *b = b_;
+	return util_as_int(b) - util_as_int(a);
+}
+
+static void add_people_count(struct strbuf *out, struct string_list *people)
+{
+	if (people->nr == 1)
+		strbuf_addf(out, "%s", people->items[0].string);
+	else if (people->nr == 2)
+		strbuf_addf(out, "%s (%d) and %s (%d)",
+			    people->items[0].string,
+			    (int)util_as_int(&people->items[0]),
+			    people->items[1].string,
+			    (int)util_as_int(&people->items[1]));
+	else if (people->nr)
+		strbuf_addf(out, "%s (%d) and others",
+			    people->items[0].string,
+			    (int)util_as_int(&people->items[0]));
+}
+
+static int committer_is_me(const char *name)
+{
+	int namelen = strlen(name);
+	const char *me = git_committer_info(IDENT_NO_DATE);
+	return (me && !memcmp(me, name, namelen) &&
+		!memcmp(me + namelen, " <", 2));
+}
+
+static void add_people_info(struct strbuf *out,
+			    struct string_list *authors,
+			    struct string_list *committers)
+{
+	if (authors->nr)
+		qsort(authors->items,
+		      authors->nr, sizeof(authors->items[0]),
+		      cmp_string_list_util_as_int);
+	if (committers->nr)
+		qsort(committers->items,
+		      committers->nr, sizeof(committers->items[0]),
+		      cmp_string_list_util_as_int);
+
+	if (authors->nr) {
+		strbuf_addstr(out, "\nBy ");
+		add_people_count(out, authors);
+	}
+	if (committers->nr == 1 &&
+	    committer_is_me(committers->items->string))
+		return;
+	strbuf_addstr(out, "\nvia ");
+	add_people_count(out, committers);
+}
+
 static void shortlog(const char *name,
 		     struct origin_data *origin_data,
 		     struct commit *head,
@@ -190,6 +277,8 @@ static void shortlog(const char *name,
 	struct commit *commit;
 	struct object *branch;
 	struct string_list subjects = STRING_LIST_INIT_DUP;
+	struct string_list authors = STRING_LIST_INIT_DUP;
+	struct string_list committers = STRING_LIST_INIT_DUP;
 	int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
 	struct strbuf sb = STRBUF_INIT;
 	const unsigned char *sha1 = origin_data->sha1;
@@ -199,7 +288,6 @@ static void shortlog(const char *name,
 		return;
 
 	setup_revisions(0, NULL, rev, NULL);
-	rev->ignore_merges = 1;
 	add_pending_object(rev, branch, name);
 	add_pending_object(rev, &head->object, "^HEAD");
 	head->object.flags |= UNINTERESTING;
@@ -208,10 +296,15 @@ static void shortlog(const char *name,
 	while ((commit = get_revision(rev)) != NULL) {
 		struct pretty_print_context ctx = {0};
 
-		/* ignore merges */
-		if (commit->parents && commit->parents->next)
+		if (commit->parents && commit->parents->next) {
+			/* do not list a merge but count committer */
+			record_person('c', &committers, commit);
 			continue;
-
+		}
+		if (!count)
+			/* the 'tip' committer */
+			record_person('c', &committers, commit);
+		record_person('a', &authors, commit);
 		count++;
 		if (subjects.nr > limit)
 			continue;
@@ -226,6 +319,7 @@ static void shortlog(const char *name,
 			string_list_append(&subjects, strbuf_detach(&sb, NULL));
 	}
 
+	add_people_info(out, &authors, &committers);
 	if (count > limit)
 		strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
 	else
@@ -246,6 +340,7 @@ static void shortlog(const char *name,
 	rev->commits = NULL;
 	rev->pending.nr = 0;
 
+	string_list_clear(&authors, 0);
 	string_list_clear(&subjects, 0);
 }
 
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 9a16806921..b90015df1c 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -35,15 +35,18 @@ test_expect_success setup '
 
 	echo "l3" >two &&
 	test_tick &&
-	git commit -a -m "Left #3" &&
+	GIT_COMMITTER_NAME="Another Committer" \
+	GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #3" &&
 
 	echo "l4" >two &&
 	test_tick &&
-	git commit -a -m "Left #4" &&
+	GIT_COMMITTER_NAME="Another Committer" \
+	GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #4" &&
 
 	echo "l5" >two &&
 	test_tick &&
-	git commit -a -m "Left #5" &&
+	GIT_COMMITTER_NAME="Another Committer" \
+	GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #5" &&
 	git tag tag-l5 &&
 
 	git checkout right &&
@@ -99,6 +102,8 @@ test_expect_success '[merge] summary/log configuration' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -144,6 +149,8 @@ test_expect_success 'merge.log=3 limits shortlog length' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* left: (5 commits)
 	  Left #5
 	  Left #4
@@ -159,6 +166,8 @@ test_expect_success 'merge.log=5 shows all 5 commits' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -181,6 +190,8 @@ test_expect_success '--log=3 limits shortlog length' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* left: (5 commits)
 	  Left #5
 	  Left #4
@@ -196,6 +207,8 @@ test_expect_success '--log=5 shows all 5 commits' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -225,6 +238,8 @@ test_expect_success 'fmt-merge-msg -m' '
 	cat >expected.log <<-EOF &&
 	Sync with left
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* ${apos}left${apos} of $(pwd):
 	  Left #5
 	  Left #4
@@ -256,6 +271,8 @@ test_expect_success 'setup: expected shortlog for two branches' '
 	cat >expected <<-EOF
 	Merge branches ${apos}left${apos} and ${apos}right${apos}
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -263,6 +280,7 @@ test_expect_success 'setup: expected shortlog for two branches' '
 	  Common #2
 	  Common #1
 
+	By A U Thor
 	* right:
 	  Right #5
 	  Right #4
@@ -353,6 +371,7 @@ test_expect_success 'merge-msg tag' '
 	cat >expected <<-EOF &&
 	Merge tag ${apos}tag-r3${apos}
 
+	By A U Thor
 	* tag ${apos}tag-r3${apos}:
 	  Right #3
 	  Common #2
@@ -374,11 +393,14 @@ test_expect_success 'merge-msg two tags' '
 	cat >expected <<-EOF &&
 	Merge tags ${apos}tag-r3${apos} and ${apos}tag-l5${apos}
 
+	By A U Thor
 	* tag ${apos}tag-r3${apos}:
 	  Right #3
 	  Common #2
 	  Common #1
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* tag ${apos}tag-l5${apos}:
 	  Left #5
 	  Left #4
@@ -402,11 +424,14 @@ test_expect_success 'merge-msg tag and branch' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}, tag ${apos}tag-r3${apos}
 
+	By A U Thor
 	* tag ${apos}tag-r3${apos}:
 	  Right #3
 	  Common #2
 	  Common #1
 
+	By Another Author (3) and A U Thor (2)
+	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -431,6 +456,7 @@ test_expect_success 'merge-msg lots of commits' '
 		cat <<-EOF &&
 		Merge branch ${apos}long${apos}
 
+		By A U Thor
 		* long: (35 commits)
 		EOF
 
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 9e27bbf902..e09b932650 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -58,6 +58,7 @@ create_merge_msgs () {
 	} >squash.1-5-9 &&
 	echo >msg.nolog &&
 	{
+		echo "By A U Thor" &&
 		echo "* tag 'c3':" &&
 		echo "  commit 3" &&
 		echo
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 89619cf446..b84cea3498 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -11,6 +11,7 @@ create_merge_msgs() {
 
 	cp exp.subject exp.log &&
 	echo >>exp.log "" &&
+	echo >>exp.log "By A U Thor" &&
 	echo >>exp.log "* tag 'c2':" &&
 	echo >>exp.log "  c2"
 }

From 780cab1c6fab45d28110c995b64eb9372edbbad5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Torsten=20B=C3=B6gershausen?= 
Date: Tue, 6 Mar 2012 21:39:10 +0100
Subject: [PATCH 3017/3720] t0204: remove a test that checks undefined
 behaviour
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The test "gettext: Emitting ISO-8859-1 from our UTF-8 *.mo files /
Runes" asks the i18n machinery to show UTF-8 encoded text in a
ISO-8859-1 locale with code points that don't fit into ISO-8859-1.

This is asking for an impossible and observing the undefined
behaviour, which is not a useful test.  Some systems convert these
code points into question marks while others don't support any i18n
and show the given template string back.  But there is no reason to
insist that the fall back behaviour must be one of these two.

Remove it.

Signed-off-by: Torsten Bögershausen 
Signed-off-by: Junio C Hamano 
---
 t/t0204-gettext-reencode-sanity.sh | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/t/t0204-gettext-reencode-sanity.sh b/t/t0204-gettext-reencode-sanity.sh
index 189af90c02..b0628a124a 100755
--- a/t/t0204-gettext-reencode-sanity.sh
+++ b/t/t0204-gettext-reencode-sanity.sh
@@ -26,20 +26,6 @@ test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UT
     test_cmp expect actual
 '
 
-test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UTF-8 *.mo files / Runes' '
-    LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "TEST: Old English Runes" >runes &&
-
-	if grep "^TEST: Old English Runes$" runes
-	then
-		say "Your system can not handle this complexity and returns the string as-is"
-	else
-		# Both Solaris and GNU libintl will return this stream of
-		# question marks, so it is s probably portable enough
-		printf "TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????" >runes-expect &&
-		test_cmp runes-expect runes
-	fi
-'
-
 test_expect_success GETTEXT_LOCALE 'gettext: Fetching a UTF-8 msgid -> UTF-8' '
     printf "TILRAUN: ‚einfaldar‘ og „tvöfaldar“ gæsalappir" >expect &&
     LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: ‘single’ and “double” quotes" >actual &&

From 9db89688f00d5ba92fdb55e8ef60c5cb7397df8b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= 
Date: Tue, 6 Mar 2012 20:37:23 +0100
Subject: [PATCH 3018/3720] unpack-trees: plug minor memory leak

The allocations made by unpack_nondirectories() using create_ce_entry()
are never freed.

In the non-merge case, we duplicate them using add_entry() and later
only look at the first allocated element (src[0]), perhaps even only
by mistake.  Split out the actual addition from add_entry() into the
new helper do_add_entry() and call this non-duplicating function
instead of add_entry() to avoid the leak.

Valgrind reports this for the command "git archive v1.7.9" without
the patch:

  ==13372== LEAK SUMMARY:
  ==13372==    definitely lost: 230,986 bytes in 2,325 blocks
  ==13372==    indirectly lost: 0 bytes in 0 blocks
  ==13372==      possibly lost: 98 bytes in 1 blocks
  ==13372==    still reachable: 2,259,198 bytes in 3,243 blocks
  ==13372==         suppressed: 0 bytes in 0 blocks

And with the patch applied:

  ==13375== LEAK SUMMARY:
  ==13375==    definitely lost: 65 bytes in 1 blocks
  ==13375==    indirectly lost: 0 bytes in 0 blocks
  ==13375==      possibly lost: 0 bytes in 0 blocks
  ==13375==    still reachable: 2,364,417 bytes in 3,245 blocks
  ==13375==         suppressed: 0 bytes in 0 blocks

Signed-off-by: Rene Scharfe 
Signed-off-by: Junio C Hamano 
---
 unpack-trees.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/unpack-trees.c b/unpack-trees.c
index 7c9ecf665d..f9c74bdc4d 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -102,21 +102,28 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
 		opts->unpack_rejects[i].strdup_strings = 1;
 }
 
+static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+			 unsigned int set, unsigned int clear)
+{
+	clear |= CE_HASHED | CE_UNHASHED;
+
+	if (set & CE_REMOVE)
+		set |= CE_WT_REMOVE;
+
+	ce->next = NULL;
+	ce->ce_flags = (ce->ce_flags & ~clear) | set;
+	add_index_entry(&o->result, ce,
+			ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+}
+
 static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
 	unsigned int set, unsigned int clear)
 {
 	unsigned int size = ce_size(ce);
 	struct cache_entry *new = xmalloc(size);
 
-	clear |= CE_HASHED | CE_UNHASHED;
-
-	if (set & CE_REMOVE)
-		set |= CE_WT_REMOVE;
-
 	memcpy(new, ce, size);
-	new->next = NULL;
-	new->ce_flags = (new->ce_flags & ~clear) | set;
-	add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+	do_add_entry(o, new, set, clear);
 }
 
 /*
@@ -587,7 +594,7 @@ static int unpack_nondirectories(int n, unsigned long mask,
 
 	for (i = 0; i < n; i++)
 		if (src[i] && src[i] != o->df_conflict_entry)
-			add_entry(o, src[i], 0, 0);
+			do_add_entry(o, src[i], 0, 0);
 	return 0;
 }
 

From 8291cf649ee1859c19d5e52b6aaa34c0648c2af1 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Tue, 6 Mar 2012 22:39:58 -0800
Subject: [PATCH 3019/3720] fmt-merge-msg: finishing touches

Use util_as_int() helper macro in one more place to make the code
easier to read.

Also do not forget freeing the committers list.

Signed-off-by: Junio C Hamano 
---
 builtin/fmt-merge-msg.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index cbe32941ed..40b90b1fd2 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -182,6 +182,8 @@ static void add_branch_desc(struct strbuf *out, const char *name)
 	strbuf_release(&desc);
 }
 
+#define util_as_int(elem) ((intptr_t)((elem)->util))
+
 static void record_person(int which, struct string_list *people,
 			  struct commit *commit)
 {
@@ -206,13 +208,11 @@ static void record_person(int which, struct string_list *people,
 	elem = string_list_lookup(people, name_buf);
 	if (!elem) {
 		elem = string_list_insert(people, name_buf);
-		elem->util = (void *) 0;
+		elem->util = (void *)0;
 	}
-	elem->util = (void*)(((intptr_t)elem->util) + 1);
+	elem->util = (void*)(util_as_int(elem) + 1);
 }
 
-#define util_as_int(elem) ((intptr_t)((elem)->util))
-
 static int cmp_string_list_util_as_int(const void *a_, const void *b_)
 {
 	const struct string_list_item *a = a_, *b = b_;
@@ -237,10 +237,10 @@ static void add_people_count(struct strbuf *out, struct string_list *people)
 
 static int committer_is_me(const char *name)
 {
-	int namelen = strlen(name);
 	const char *me = git_committer_info(IDENT_NO_DATE);
-	return (me && !memcmp(me, name, namelen) &&
-		!memcmp(me + namelen, " <", 2));
+	return (me &&
+		(me = skip_prefix(me, name)) != NULL &&
+		skip_prefix(me, " <"));
 }
 
 static void add_people_info(struct strbuf *out,
@@ -341,6 +341,7 @@ static void shortlog(const char *name,
 	rev->pending.nr = 0;
 
 	string_list_clear(&authors, 0);
+	string_list_clear(&committers, 0);
 	string_list_clear(&subjects, 0);
 }
 

From 6d483908f32090e82a52325c3407776a518ed2a3 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Thu, 8 Mar 2012 13:29:55 -0800
Subject: [PATCH 3020/3720] fmt-merge-msg.c: make util_as_int() return "int"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

As its name says, the return value from util_as_int() should be
usable where an int is called for without casting.

Spotted-by: René Scharfe
Signed-off-by: Junio C Hamano 
---
 builtin/fmt-merge-msg.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 40b90b1fd2..8ddefb39db 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -182,7 +182,7 @@ static void add_branch_desc(struct strbuf *out, const char *name)
 	strbuf_release(&desc);
 }
 
-#define util_as_int(elem) ((intptr_t)((elem)->util))
+#define util_as_int(elem) ((int)((elem)->util))
 
 static void record_person(int which, struct string_list *people,
 			  struct commit *commit)
@@ -210,7 +210,7 @@ static void record_person(int which, struct string_list *people,
 		elem = string_list_insert(people, name_buf);
 		elem->util = (void *)0;
 	}
-	elem->util = (void*)(util_as_int(elem) + 1);
+	elem->util = (void*)((intptr_t)(util_as_int(elem) + 1));
 }
 
 static int cmp_string_list_util_as_int(const void *a_, const void *b_)
@@ -226,13 +226,13 @@ static void add_people_count(struct strbuf *out, struct string_list *people)
 	else if (people->nr == 2)
 		strbuf_addf(out, "%s (%d) and %s (%d)",
 			    people->items[0].string,
-			    (int)util_as_int(&people->items[0]),
+			    util_as_int(&people->items[0]),
 			    people->items[1].string,
-			    (int)util_as_int(&people->items[1]));
+			    util_as_int(&people->items[1]));
 	else if (people->nr)
 		strbuf_addf(out, "%s (%d) and others",
 			    people->items[0].string,
-			    (int)util_as_int(&people->items[0]));
+			    util_as_int(&people->items[0]));
 }
 
 static int committer_is_me(const char *name)

From 0395e4b995f57cefd982ec1c8126db625a2c12c5 Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Fri, 9 Mar 2012 16:45:50 -0800
Subject: [PATCH 3021/3720] Revert "Merge branch
 'tb/maint-remove-irrelevant-i18n-test' into next"

This reverts commit 23f2dd18b9e5bf5f7deb4f3480b03edd4841ea71,
reversing changes made to 73259221659f2148d90787765242771f667280a6,
as it may turn out to be useful to just observe how the platforms
behave when asked to do an impossible transliteration.
---
 t/t0204-gettext-reencode-sanity.sh | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/t/t0204-gettext-reencode-sanity.sh b/t/t0204-gettext-reencode-sanity.sh
index b0628a124a..189af90c02 100755
--- a/t/t0204-gettext-reencode-sanity.sh
+++ b/t/t0204-gettext-reencode-sanity.sh
@@ -26,6 +26,20 @@ test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UT
     test_cmp expect actual
 '
 
+test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UTF-8 *.mo files / Runes' '
+    LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "TEST: Old English Runes" >runes &&
+
+	if grep "^TEST: Old English Runes$" runes
+	then
+		say "Your system can not handle this complexity and returns the string as-is"
+	else
+		# Both Solaris and GNU libintl will return this stream of
+		# question marks, so it is s probably portable enough
+		printf "TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????" >runes-expect &&
+		test_cmp runes-expect runes
+	fi
+'
+
 test_expect_success GETTEXT_LOCALE 'gettext: Fetching a UTF-8 msgid -> UTF-8' '
     printf "TILRAUN: ‚einfaldar‘ og „tvöfaldar“ gæsalappir" >expect &&
     LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: ‘single’ and “double” quotes" >actual &&

From 5293b54a218cc9ec7c667f64d4b10cd0d985203f Mon Sep 17 00:00:00 2001
From: Matthieu Moy 
Date: Fri, 9 Mar 2012 09:31:26 +0100
Subject: [PATCH 3022/3720] push: start warning upcoming default change for
 push.default

In preparation for flipping the default to the "upstream" mode from
the "matching" mode that is the historical default, start warning
users when they rely on unconfigured "git push" to default to the
"matching" mode.

Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 builtin/push.c | 25 +++++++++++++++++++++++++
 cache.h        |  3 ++-
 environment.c  |  2 +-
 3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index d315475f16..7f933d193d 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -91,10 +91,35 @@ static void setup_push_upstream(struct remote *remote)
 	add_refspec(refspec.buf);
 }
 
+static char warn_unspecified_push_default_msg[] =
+N_("push.default is unset; its implicit value is changing in\n"
+   "Git 2.0 from 'matching' to 'upstream'. To squelch this message\n"
+   "and maintain the current behavior after the default changes, use:\n"
+   "\n"
+   "  git config --global push.default matching\n"
+   "\n"
+   "To squelch this message and adopt the new behavior now, use:\n"
+   "\n"
+   "  git config --global push.default upstream\n"
+   "\n"
+   "See 'git help config' and search for 'push.default' for further information.");
+
+static void warn_unspecified_push_default_configuration(void)
+{
+	static int warn_once;
+
+	if (warn_once++)
+		return;
+	warning("%s\n", _(warn_unspecified_push_default_msg));
+}
+
 static void setup_default_push_refspecs(struct remote *remote)
 {
 	switch (push_default) {
 	default:
+	case PUSH_DEFAULT_UNSPECIFIED:
+		warn_unspecified_push_default_configuration();
+		/* fallthru */
 	case PUSH_DEFAULT_MATCHING:
 		add_refspec(":");
 		break;
diff --git a/cache.h b/cache.h
index e5e1aa4e15..35f30752c6 100644
--- a/cache.h
+++ b/cache.h
@@ -625,7 +625,8 @@ enum push_default_type {
 	PUSH_DEFAULT_NOTHING = 0,
 	PUSH_DEFAULT_MATCHING,
 	PUSH_DEFAULT_UPSTREAM,
-	PUSH_DEFAULT_CURRENT
+	PUSH_DEFAULT_CURRENT,
+	PUSH_DEFAULT_UNSPECIFIED
 };
 
 extern enum branch_track git_branch_track;
diff --git a/environment.c b/environment.c
index c93b8f44df..d7e6c65763 100644
--- a/environment.c
+++ b/environment.c
@@ -52,7 +52,7 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
 unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
 enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
 enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
-enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
+enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
 #ifndef OBJECT_CREATION_MODE
 #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
 #endif

From 1dce46129c295c50cd717bc31ccbe7fafb9ab703 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 11 Feb 2012 00:58:37 +0100
Subject: [PATCH 3023/3720] Win32: fix deletion of .git/objects sub-directories
 in git-repack

On Windows XP (not Win7), directories cannot be deleted while a find handle
is open, causing "Deletion of directory '...' failed. Should I try again?"
prompts in git-repack and git-gc.

Prior to 19d1e75d "Win32: Unicode file name support (except dirent)",
these failures were silently ignored due to strbuf_free in is_dir_empty
resetting GetLastError to ERROR_SUCCESS.

Close find handles properly before trying to delete directories.

Reported-by: John Chen 
Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..71a04c5a30 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -238,11 +238,12 @@ static int is_dir_empty(const char *path)
 		return GetLastError() == ERROR_NO_MORE_FILES;
 	}
 
-	while (!strcmp(findbuf.cFileName, ".") ||
-			!strcmp(findbuf.cFileName, ".."))
-		if (!FindNextFile(handle, &findbuf)) {
-			strbuf_release(&buf);
-			return GetLastError() == ERROR_NO_MORE_FILES;
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf)) {
+			DWORD err = GetLastError();
+			FindClose(handle);
+			return err == ERROR_NO_MORE_FILES;
 		}
 	FindClose(handle);
 	strbuf_release(&buf);

From 4a3859f930fcfe7612f70fc28ae5241274535a69 Mon Sep 17 00:00:00 2001
From: Matthieu Moy 
Date: Sat, 14 Jan 2012 19:55:36 +0100
Subject: [PATCH 3024/3720] bash-completion: don't add quoted space for ZSH
 (fix regression)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit a31e626 (completion: optimize refs completion) introduced a
regression for ZSH users: ref names were completed with a quoted trailing
space (i.e. "git checkout ma" completes to "git checkout master\ "). The
space is convenient for bash users since we use "-o nospace", but a
quoted space is worse than nothing. The absence of trailing space for ZSH
is a long-standing issue, that this patch is not fixing. We just fix the
regression by not appending a space when the shell is ZSH.

Original-patch-by: SZEDER Gábor 
Reported-by: Stefan Haller 
Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 contrib/completion/git-completion.bash | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index fba076dde2..f1f67b5fc4 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -508,6 +508,13 @@ __gitcomp ()
 __gitcomp_nl ()
 {
 	local IFS=$'\n'
+
+	# ZSH would quote the trailing space added with -S. bash users
+	# will appreciate the extra space to compensate the use of -o nospace.
+	if [ -n "${ZSH_VERSION-}" ] && [ "$suffix" = " " ]; then
+		suffix=""
+	fi
+
 	COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
 }
 

From f7dab8121c66b4903281be72e485c4e2aa601534 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 3025/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index be1957a5e9..073c3f67e6 100644
--- a/Makefile
+++ b/Makefile
@@ -1194,16 +1194,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From e0fbbf7fb778c43ffb22f579e380ecb7b25ec688 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 3026/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index c081657be7..58d4da28c8 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -169,6 +169,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index a8aceb5aee..099eb72a20 100644
--- a/cache.h
+++ b/cache.h
@@ -605,6 +605,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index 71a04c5a30..6dfd98295e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -279,6 +281,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -300,6 +334,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -323,17 +368,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..699a3dd395 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -113,10 +113,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -318,6 +315,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index 68d32940f3..1759695d16 100644
--- a/config.c
+++ b/config.c
@@ -752,6 +752,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index c93b8f44df..bf6f0c29ed 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index ed11ad8119..14fa4e117a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -595,4 +595,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 8e2a665a5764b2d9f773b62ac51fa55683092e1d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 3027/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 6dfd98295e..15482ba9e0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -294,6 +294,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 8fff9b79e765a9b514f83391a68327c1663c5573 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 3028/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From ba5fdec9af44df49c49e8d18b584affbed0187ae Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 3029/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 7a6038e8bc65e63492ceaa5a6826e8ee6eb5a082 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 3030/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 2561f0a08039d57f116b6e23e9cd861a33c3fcef Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 3031/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 64ef3c4013..e2cda370fa 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9499,7 +9499,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 51331f425db8349c4a5e43e60f256af749ee7165 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 3032/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From fba92aa2ea09641ea826a7d7797f2e6a4a756feb Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 3033/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 5ac2e35aaebce0a38f0f5822783b5a0964c07650 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 3034/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 58d4da28c8..24a301f2d7 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1723,6 +1723,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 0afb8b2896..1b2bf5fe66 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -89,7 +91,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -410,6 +417,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -441,6 +486,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -469,6 +521,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b5417cc951..2482796454 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -995,4 +995,40 @@ test_expect_success 'push --prune refspec' '
 	! check_push_result $the_first_commit tmp/foo tmp/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 5a6edf533ac3cafab100641233ba981d1586ab19 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 3035/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index ef30c557c7..c42fb2a7aa 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 635671562e65d541816ed713c5ce0e3679417887 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 3036/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index c42fb2a7aa..03292fd832 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 2ca15d562ab96aa44e7345c644fe6ed0faf13d46 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 3037/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index d41a9bfb14..a3991b9673 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -169,7 +169,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = given_config_file;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 15482ba9e0..6849d0c8c7 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1829,3 +1829,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 699a3dd395..ec5c25c36d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -349,3 +349,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index 1759695d16..53fd956a88 100644
--- a/config.c
+++ b/config.c
@@ -960,7 +960,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 14fa4e117a..5911e8f7eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -599,4 +599,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index 6f2aa699ad..4cb0585cde 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From c6490b558649a7a1908097206cef1fd8da799b4e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 3038/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 5783ebf3ab..1489bcff97 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From 08678c1581b1c00f0db6a76ac21f63c29db99e17 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 3039/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index faae820719..1e7ee11610 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -564,7 +564,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -736,7 +737,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -812,7 +814,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -836,7 +838,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From ce0927358bd46165368ce320936379ea5ae15d1e Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 3040/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 30ed4d74bb..0c3518205f 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 4e86ad6afa50278a0b5af0fbd2a5ce95d15cfa13 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 3041/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 099eb72a20..56113436fc 100644
--- a/cache.h
+++ b/cache.h
@@ -758,7 +758,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 6849d0c8c7..e56ca6a88a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1847,3 +1847,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index ec5c25c36d..9111ce66e7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -309,6 +309,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 5911e8f7eb..39866a76c2 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 4cb0585cde..242074b1cf 100644
--- a/path.c
+++ b/path.c
@@ -660,10 +660,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 63b0b39f6e71dc47e515d47748a8fc44a0db556b Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 3042/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index a3991b9673..490e2ea4fd 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;

From fe47e475c0d9f0e8b39a846ef02baa6551923f0b Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 3043/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e56ca6a88a..9a502bdaef 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1850,23 +1850,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From a22d46f8138ceb5b756004016911fe684b77767f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 3044/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From aea0c11918f85dc37acd83af241933401e97459c Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 3045/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index e2cda370fa..928a25d904 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -365,7 +365,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9499,18 +9499,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9521,6 +9510,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 00602cfaf3bb7ad1f4952e9f23f76c31ebd59dc3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 3046/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9a502bdaef..a0b045b27c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1208,6 +1208,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 67dbc71f72dd09bffc98db1770587ab6cf9f37b4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 3047/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9111ce66e7..60e281a7fe 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 6c0242f9e92e1dc8df49f20d5f946d9eb3cebc81 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 3048/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 8303fce94781e2c83bd163e5950284011dc370f4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 3049/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From b474259f06ede98697444d15448f1ab35048c45c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 3050/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index cea8756866..9be97ab9ae 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 1a7a7a74ee603c0930a2c43ddc8e73b2ccf50b5c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 3051/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a8b5fad266..ec97589687 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4434,6 +4434,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From b5dfca50ab2673383bef3779c0c94b1869250b2a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 3052/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index ec97589687..3c2284f611 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4449,7 +4449,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From bbcef6eb020d22d5df9e3c70e62de5b93cb6a69f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 3053/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 8ac8eb6c38..a51cf3d119 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -138,6 +139,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 2df52e3ea4c4c9606845b6d23df82bd3842ffce7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 3054/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 1b2bf5fe66..b648c14a86 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -420,7 +420,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 7b09bd77b96db627c020a55d41afbefd7ecebffe Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 3055/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 643938d905..cda17f775a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -162,6 +163,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -172,6 +189,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->source.identifier))
+			continue;
+
 		opt->output_priv = w;
 		hit |= grep_source(opt, &w->source);
 		grep_source_clear_data(&w->source);
@@ -418,6 +438,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -883,6 +906,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From c7ecfb91113c0e43d59478511234e3df376ee33d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 3056/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 073c3f67e6..c7c90e5f33 100644
--- a/Makefile
+++ b/Makefile
@@ -308,7 +308,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From b2c0b2756d1ad68500b9db0145327be623133ec3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 3057/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index a0b045b27c..cf8058537b 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1834,7 +1834,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 0c4ef4084f7e4a5c813f15b0b0764a9bf712db26 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 3058/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c7c90e5f33..5223417b99 100644
--- a/Makefile
+++ b/Makefile
@@ -2093,7 +2093,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2133,6 +2133,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 22a467013aa1193d920edaa9bdb5d24a5070e2cd Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 3059/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..18a93cba9f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From c7fb7a68bdb0fde95dd6311b0a6c4a28e9edaeca Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 3060/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index cda17f775a..3af417e76c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -974,6 +974,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From 414cf088b74cd8473a4c31391d7b810549c26c7c Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 3061/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 06d920e989e8547165179ddf4bfbcf82f4df5409 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 3062/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index cf8058537b..8eb6dd5761 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -292,7 +292,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 1f105883eaa0607e90aadd2d94f24a940b053771 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 3063/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 69d0a05eaba2de895c4386b949ea4bd200371174 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 3064/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 3065/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index efc86ad4e0..5bec652114 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -832,12 +832,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 3066/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 08e13d72d2b7e61cc9708754c4ac546ed97ac893 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 3067/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 5d8e4e6c89..d9fc4be050 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 3068/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 5223417b99..7879caa174 100644
--- a/Makefile
+++ b/Makefile
@@ -1188,6 +1188,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1281,6 +1282,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 5dc50420f7c0bade34849bf19f976978d2fe4b1b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 3069/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 6a5d1af1efd7d7eb831bf7938661c1625a0003b3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 3070/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From f4e813cef4dc5a8dd02345537e6602ec7aa3107e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 3071/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From c6a9902db2b788e0ee7d96a2a6a7280b48593cf9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 3072/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 0106a17fbb8f16b2f51cf83fc360c2f6ca1e22db Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 3073/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8eb6dd5761..4c94b45fff 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -476,7 +476,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From f606b470c23abf924169a887d3019004d268a5aa Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 3074/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 4c94b45fff..41674323d5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,3 +1876,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 60e281a7fe..da9c53583a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 3efb921411e1560c51708ee2413bfd779428279f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 3075/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 41674323d5..d207b6dc92 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1877,6 +1877,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 1a50baa1a13a40a63fdfad4dc903d0013280c112 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 3076/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 3c2284f611..e032b69aff 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6812,7 +6812,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6860,6 +6872,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 137a8f4cc6cfe4abc3ae9686887dc571840a414d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 3077/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e032b69aff..5dbbcfa0ba 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4434,7 +4434,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 3f134776b7467a602dcc86074a77d14373fae207 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 3078/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 5dbbcfa0ba..14a133ae00 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6925,7 +6925,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 3e4f9a0db113de2a3f9db4abb786345e50dab41f Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 3079/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index d207b6dc92..116d214f7c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -818,7 +818,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From d25f211be7d5f461a2f7f85221a5fc41df5291ed Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 3080/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index da9c53583a..1f9f35f63d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From c87297bdea98cec159ea31758734437655eaa384 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 3081/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 2a10047eb7..be1b098be0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -113,7 +114,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -278,7 +284,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From cf6a77e2a618abaf9d4083fddf7963d14a105c5a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 3082/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 24a301f2d7..beaca417a9 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -699,6 +699,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index be1b098be0..34b47c4fb2 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 7c80710171c7fca1ad167530537100f2a61fb552 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 3083/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1f9f35f63d..407bad231b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 39866a76c2..76c5eef420 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From 5e4f4c9569b2400f228d49dab310b40c8211c97e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 3084/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From 82c389c7cda0a0b6f7881a4baf540d7669b9d5de Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 3085/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 7879caa174..3ad3062305 100644
--- a/Makefile
+++ b/Makefile
@@ -1186,6 +1186,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From f7c91d672ed98874ad12a854e878d9620c0f80e3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 3086/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From b46eeaf0a7b773ae6ff07793036cd6247d3cded3 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 3087/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3ad3062305..4dc9256967 100644
--- a/Makefile
+++ b/Makefile
@@ -1264,7 +1264,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From e5ee6d6b348ecfad25eee98395d181872aa48bc4 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 16:50:50 +0000
Subject: [PATCH 3088/3720] gitk: fix the display of files when filtered by
 path

Launching 'gitk -- .' or 'gitk -- ..\t' restricts the display to files
under the given directory but the file list is left empty. This is because
the path_filter function fails to match the filenames which are relative
to the working tree to the filter which is filessytem relative.
This solves the problem by making both names fully qualified filesystem
paths before performing the comparison.

Signed-off-by: Pat Thoyts 
Tested-by: David Aguilar 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 928a25d904..77c38b01b6 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -14,6 +14,26 @@ proc hasworktree {} {
 		  [exec git rev-parse --is-inside-git-dir] == "false"}]
 }
 
+proc gitworktree {} {
+    variable _gitworktree
+    if {[info exists _gitworktree]} {
+	return $_gitworktree
+    }
+    # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+    if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+        # try to set work tree from environment, core.worktree or use
+        # cdup to obtain a relative path to the top of the worktree. If
+        # run from the top, the ./ prefix ensures normalize expands pwd.
+        if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+	    catch {set _gitworktree [exec git config --get core.worktree]}
+	    if {$_gitworktree eq ""} {
+		set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+	    }
+        }
+    }
+    return $_gitworktree
+}
+
 # A simple scheduler for compute-intensive stuff.
 # The aim is to make sure that event handlers for GUI actions can
 # run at least every 50-100 ms.  Unfortunately fileevent handlers are
@@ -7393,19 +7413,15 @@ proc startdiff {ids} {
     }
 }
 
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
 proc path_filter {filter name} {
+    set worktree [gitworktree]
     foreach p $filter {
-	set l [string length $p]
-	if {[string index $p end] eq "/"} {
-	    if {[string compare -length $l $p $name] == 0} {
-		return 1
-	    }
-	} else {
-	    if {[string compare -length $l $p $name] == 0 &&
-		([string length $name] == $l ||
-		 [string index $name $l] eq "/")} {
-		return 1
-	    }
+	set fq_p [file normalize $p]
+	set fq_n [file normalize [file join $worktree $name]]
+	if {[string match [file normalize $fq_p]* $fq_n]} {
+	    return 1
 	}
     }
     return 0

From 6bcef28c43c02bd424c9a870ddd8178ed49d2859 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 3089/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 4dc9256967..c82f297f0f 100644
--- a/Makefile
+++ b/Makefile
@@ -1301,6 +1301,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From 43f0904cc75becdaba1d5899a52e3794c4577afa Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 3090/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From b7f7ad128196b10564f2311e8131214a4e118571 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 6 Jan 2012 13:56:09 -0600
Subject: [PATCH 3091/3720] Install Git/I18N.pm even in the absence of Perl's
 MakeMaker

The telltale was that t0202 could not find I18N.pm on msysGit.

Signed-off-by: Johannes Schindelin 
---
 perl/Makefile | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/perl/Makefile b/perl/Makefile
index b2977cd0bc..91848f3d3c 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -24,13 +24,15 @@ ifdef NO_PERL_MAKEMAKER
 instdir_SQ = $(subst ','\'',$(prefix)/lib)
 $(makfile): ../GIT-CFLAGS Makefile
 	echo all: private-Error.pm Git.pm > $@
-	echo '	mkdir -p blib/lib' >> $@
+	echo '	mkdir -p blib/lib/Git' >> $@
+	echo '	$(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@
 	echo '	$(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@
 	echo '	$(RM) blib/lib/Error.pm' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
 	echo '	cp private-Error.pm blib/lib/Error.pm' >> $@
 	echo install: >> $@
-	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)"' >> $@
+	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
+	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm "$$(DESTDIR)$(instdir_SQ)/Git/"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm "$$(DESTDIR)$(instdir_SQ)"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \

From 46e4bd1087ede26022363aa963100da17324b079 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 9 Jan 2012 19:16:30 +0100
Subject: [PATCH 3092/3720] Windows/i18n: rename $path to prevent clashes with
 $PATH

Environment variables on Windows are case-insensitive. Rename '$path' in
all calls to eval_gettext to $modulepath so that it is not mistakenly
expanded to the value of the $PATH variable.

[jes: this happens to fix t7406/t7407 on Windows]
[pt: squashed in fix for substitution order error that broke t7400]

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
---
 git-submodule.sh | 52 ++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index dccd0f663a..8037dbffd0 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -105,7 +105,7 @@ module_name()
 	name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
 	test -z "$name" &&
-	die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+	die "$(modulepath=$path eval_gettext "No submodule mapping found in .gitmodules for path '\$modulepath'")"
 	echo "$name"
 }
 
@@ -146,7 +146,7 @@ module_clone()
 		mkdir -p "$gitdir_base"
 		git clone $quiet -n ${reference:+"$reference"} \
 			--separate-git-dir "$gitdir" "$url" "$path" ||
-		die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+		die "$(eval_gettext "Clone of '\$url' into submodule path '\$modulepath' failed")"
 	fi
 
 	a=$(cd "$gitdir" && pwd)/
@@ -261,13 +261,13 @@ cmd_add()
 			s|/*$||
 		')
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
-	die "$(eval_gettext "'\$path' already exists in the index")"
+	die "$(modulepath=$path eval_gettext "'\$modulepath' already exists in the index")"
 
 	if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
 	then
 		cat >&2 </dev/null) &&
 					 test -z "$rev") || git-fetch)) ||
-				die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
+				die "$(modulepath=$path eval_gettext "Unable to fetch in submodule path '\$modulepath'")"
 			fi
 
 			# Is this something we just cloned?
@@ -564,20 +564,20 @@ Maybe you want to use 'update --init'?")"
 			case "$update_module" in
 			rebase)
 				command="git rebase"
-				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to rebase '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': rebased into '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			merge)
 				command="git merge"
-				die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to merge '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': merged in '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			*)
 				command="git checkout $subforce -q"
-				die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to checkout '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': checked out '\$sha1'")"
 				;;
 			esac
 
@@ -599,7 +599,7 @@ Maybe you want to use 'update --init'?")"
 			res=$?
 			if test $res -gt 0
 			then
-				die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+				die_msg="$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 				if test $res -eq 1
 				then
 					err="${err};$die_msg"
@@ -926,7 +926,7 @@ cmd_status()
 				cd "$path" &&
 				eval cmd_status "$orig_args"
 			) ||
-			die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+			die "$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 		fi
 	done
 }

From 6f03ff008ea913ddf760ca70361aaaadcbab7728 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 14:56:49 +0000
Subject: [PATCH 3093/3720] gitk: use a tabbed dialog to edit preferences

This commit converts the user preferences dialog into a tabbed property
sheet grouping general properties, colours and font selections onto
separate pages. The previous implementation was exceeding the screen
height on some systems and this avoids such problems and permits extension
using new pages in the future.

If themed Tk is unavailable or undesired a reasonable facsimile of the
tabbed notebook widget is used instead.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 256 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 160 insertions(+), 96 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 77c38b01b6..dcae0a7547 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10805,6 +10805,139 @@ proc chg_fontparam {v sub op} {
     font config sample -$sub $fontparam($sub)
 }
 
+# Create a property sheet tab page
+proc create_prefs_page {w} {
+    global NS
+    set parent [join [lrange [split $w .] 0 end-1] .]
+    if {[winfo class $parent] eq "TNotebook"} {
+	${NS}::frame $w
+    } else {
+	${NS}::labelframe $w
+    }
+}
+
+proc prefspage_general {notebook} {
+    global NS maxwidth maxgraphpct showneartags showlocalchanges
+    global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
+    global hideremotes want_ttk have_ttk
+
+    set page [create_prefs_page $notebook.general]
+
+    ${NS}::label $page.ldisp -text [mc "Commit list display options"]
+    grid $page.ldisp - -sticky w -pady 10
+    ${NS}::label $page.spacer -text " "
+    ${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"]
+    spinbox $page.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+    grid $page.spacer $page.maxwidthl $page.maxwidth -sticky w
+    ${NS}::label $page.maxpctl -text [mc "Maximum graph width (% of pane)"]
+    spinbox $page.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+    grid x $page.maxpctl $page.maxpct -sticky w
+    ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \
+	-variable showlocalchanges
+    grid x $page.showlocal -sticky w
+    ${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \
+	-variable autoselect
+    spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
+    grid x $page.autoselect $page.autosellen -sticky w
+    ${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \
+	-variable hideremotes
+    grid x $page.hideremotes -sticky w
+
+    ${NS}::label $page.ddisp -text [mc "Diff display options"]
+    grid $page.ddisp - -sticky w -pady 10
+    ${NS}::label $page.tabstopl -text [mc "Tab spacing"]
+    spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
+    grid x $page.tabstopl $page.tabstop -sticky w
+    ${NS}::checkbutton $page.ntag -text [mc "Display nearby tags"] \
+	-variable showneartags
+    grid x $page.ntag -sticky w
+    ${NS}::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \
+	-variable limitdiffs
+    grid x $page.ldiff -sticky w
+    ${NS}::checkbutton $page.lattr -text [mc "Support per-file encodings"] \
+	-variable perfile_attrs
+    grid x $page.lattr -sticky w
+
+    ${NS}::entry $page.extdifft -textvariable extdifftool
+    ${NS}::frame $page.extdifff
+    ${NS}::label $page.extdifff.l -text [mc "External diff tool" ]
+    ${NS}::button $page.extdifff.b -text [mc "Choose..."] -command choose_extdiff
+    pack $page.extdifff.l $page.extdifff.b -side left
+    pack configure $page.extdifff.l -padx 10
+    grid x $page.extdifff $page.extdifft -sticky ew
+
+    ${NS}::label $page.lgen -text [mc "General options"]
+    grid $page.lgen - -sticky w -pady 10
+    ${NS}::checkbutton $page.want_ttk -variable want_ttk \
+	-text [mc "Use themed widgets"]
+    if {$have_ttk} {
+	${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
+    } else {
+	${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
+    }
+    grid x $page.want_ttk $page.ttk_note -sticky w
+    return $page
+}
+
+proc prefspage_colors {notebook} {
+    global NS uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+
+    set page [create_prefs_page $notebook.colors]
+
+    ${NS}::label $page.cdisp -text [mc "Colors: press to choose"]
+    grid $page.cdisp - -sticky w -pady 10
+    label $page.ui -padx 40 -relief sunk -background $uicolor
+    ${NS}::button $page.uibut -text [mc "Interface"] \
+       -command [list choosecolor uicolor {} $page.ui [mc "interface"] setui]
+    grid x $page.uibut $page.ui -sticky w
+    label $page.bg -padx 40 -relief sunk -background $bgcolor
+    ${NS}::button $page.bgbut -text [mc "Background"] \
+	-command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
+    grid x $page.bgbut $page.bg -sticky w
+    label $page.fg -padx 40 -relief sunk -background $fgcolor
+    ${NS}::button $page.fgbut -text [mc "Foreground"] \
+	-command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
+    grid x $page.fgbut $page.fg -sticky w
+    label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
+    ${NS}::button $page.diffoldbut -text [mc "Diff: old lines"] \
+	-command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
+		      [list $ctext tag conf d0 -foreground]]
+    grid x $page.diffoldbut $page.diffold -sticky w
+    label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
+    ${NS}::button $page.diffnewbut -text [mc "Diff: new lines"] \
+	-command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
+		      [list $ctext tag conf dresult -foreground]]
+    grid x $page.diffnewbut $page.diffnew -sticky w
+    label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
+    ${NS}::button $page.hunksepbut -text [mc "Diff: hunk header"] \
+	-command [list choosecolor diffcolors 2 $page.hunksep \
+		      [mc "diff hunk header"] \
+		      [list $ctext tag conf hunksep -foreground]]
+    grid x $page.hunksepbut $page.hunksep -sticky w
+    label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor
+    ${NS}::button $page.markbgbut -text [mc "Marked line bg"] \
+	-command [list choosecolor markbgcolor {} $page.markbgsep \
+		      [mc "marked line background"] \
+		      [list $ctext tag conf omark -background]]
+    grid x $page.markbgbut $page.markbgsep -sticky w
+    label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor
+    ${NS}::button $page.selbgbut -text [mc "Select bg"] \
+	-command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
+    grid x $page.selbgbut $page.selbgsep -sticky w
+    return $page
+}
+
+proc prefspage_fonts {notebook} {
+    global NS
+    set page [create_prefs_page $notebook.fonts]
+    ${NS}::label $page.cfont -text [mc "Fonts: press to choose"]
+    grid $page.cfont - -sticky w -pady 10
+    mkfontdisp mainfont $page [mc "Main font"]
+    mkfontdisp textfont $page [mc "Diff display font"]
+    mkfontdisp uifont $page [mc "User interface font"]
+    return $page
+}
+
 proc doprefs {} {
     global maxwidth maxgraphpct use_ttk NS
     global oldprefs prefstop showneartags showlocalchanges
@@ -10825,106 +10958,37 @@ proc doprefs {} {
     ttk_toplevel $top
     wm title $top [mc "Gitk preferences"]
     make_transient $top .
-    ${NS}::label $top.ldisp -text [mc "Commit list display options"]
-    grid $top.ldisp - -sticky w -pady 10
-    ${NS}::label $top.spacer -text " "
-    ${NS}::label $top.maxwidthl -text [mc "Maximum graph width (lines)"]
-    spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
-    grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
-    ${NS}::label $top.maxpctl -text [mc "Maximum graph width (% of pane)"]
-    spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
-    grid x $top.maxpctl $top.maxpct -sticky w
-    ${NS}::checkbutton $top.showlocal -text [mc "Show local changes"] \
-	-variable showlocalchanges
-    grid x $top.showlocal -sticky w
-    ${NS}::checkbutton $top.autoselect -text [mc "Auto-select SHA1 (length)"] \
-	-variable autoselect
-    spinbox $top.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
-    grid x $top.autoselect $top.autosellen -sticky w
-    ${NS}::checkbutton $top.hideremotes -text [mc "Hide remote refs"] \
-	-variable hideremotes
-    grid x $top.hideremotes -sticky w
 
-    ${NS}::label $top.ddisp -text [mc "Diff display options"]
-    grid $top.ddisp - -sticky w -pady 10
-    ${NS}::label $top.tabstopl -text [mc "Tab spacing"]
-    spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
-    grid x $top.tabstopl $top.tabstop -sticky w
-    ${NS}::checkbutton $top.ntag -text [mc "Display nearby tags"] \
-	-variable showneartags
-    grid x $top.ntag -sticky w
-    ${NS}::checkbutton $top.ldiff -text [mc "Limit diffs to listed paths"] \
-	-variable limitdiffs
-    grid x $top.ldiff -sticky w
-    ${NS}::checkbutton $top.lattr -text [mc "Support per-file encodings"] \
-	-variable perfile_attrs
-    grid x $top.lattr -sticky w
-
-    ${NS}::entry $top.extdifft -textvariable extdifftool
-    ${NS}::frame $top.extdifff
-    ${NS}::label $top.extdifff.l -text [mc "External diff tool" ]
-    ${NS}::button $top.extdifff.b -text [mc "Choose..."] -command choose_extdiff
-    pack $top.extdifff.l $top.extdifff.b -side left
-    pack configure $top.extdifff.l -padx 10
-    grid x $top.extdifff $top.extdifft -sticky ew
-
-    ${NS}::label $top.lgen -text [mc "General options"]
-    grid $top.lgen - -sticky w -pady 10
-    ${NS}::checkbutton $top.want_ttk -variable want_ttk \
-	-text [mc "Use themed widgets"]
-    if {$have_ttk} {
-	${NS}::label $top.ttk_note -text [mc "(change requires restart)"]
+    if {[set use_notebook [expr {$use_ttk && [info command ::ttk::notebook] ne ""}]]} {
+	set notebook [ttk::notebook $top.notebook]
     } else {
-	${NS}::label $top.ttk_note -text [mc "(currently unavailable)"]
+	set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat]
     }
-    grid x $top.want_ttk $top.ttk_note -sticky w
 
-    ${NS}::label $top.cdisp -text [mc "Colors: press to choose"]
-    grid $top.cdisp - -sticky w -pady 10
-    label $top.ui -padx 40 -relief sunk -background $uicolor
-    ${NS}::button $top.uibut -text [mc "Interface"] \
-       -command [list choosecolor uicolor {} $top.ui [mc "interface"] setui]
-    grid x $top.uibut $top.ui -sticky w
-    label $top.bg -padx 40 -relief sunk -background $bgcolor
-    ${NS}::button $top.bgbut -text [mc "Background"] \
-	-command [list choosecolor bgcolor {} $top.bg [mc "background"] setbg]
-    grid x $top.bgbut $top.bg -sticky w
-    label $top.fg -padx 40 -relief sunk -background $fgcolor
-    ${NS}::button $top.fgbut -text [mc "Foreground"] \
-	-command [list choosecolor fgcolor {} $top.fg [mc "foreground"] setfg]
-    grid x $top.fgbut $top.fg -sticky w
-    label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
-    ${NS}::button $top.diffoldbut -text [mc "Diff: old lines"] \
-	-command [list choosecolor diffcolors 0 $top.diffold [mc "diff old lines"] \
-		      [list $ctext tag conf d0 -foreground]]
-    grid x $top.diffoldbut $top.diffold -sticky w
-    label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
-    ${NS}::button $top.diffnewbut -text [mc "Diff: new lines"] \
-	-command [list choosecolor diffcolors 1 $top.diffnew [mc "diff new lines"] \
-		      [list $ctext tag conf dresult -foreground]]
-    grid x $top.diffnewbut $top.diffnew -sticky w
-    label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
-    ${NS}::button $top.hunksepbut -text [mc "Diff: hunk header"] \
-	-command [list choosecolor diffcolors 2 $top.hunksep \
-		      [mc "diff hunk header"] \
-		      [list $ctext tag conf hunksep -foreground]]
-    grid x $top.hunksepbut $top.hunksep -sticky w
-    label $top.markbgsep -padx 40 -relief sunk -background $markbgcolor
-    ${NS}::button $top.markbgbut -text [mc "Marked line bg"] \
-	-command [list choosecolor markbgcolor {} $top.markbgsep \
-		      [mc "marked line background"] \
-		      [list $ctext tag conf omark -background]]
-    grid x $top.markbgbut $top.markbgsep -sticky w
-    label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
-    ${NS}::button $top.selbgbut -text [mc "Select bg"] \
-	-command [list choosecolor selectbgcolor {} $top.selbgsep [mc "background"] setselbg]
-    grid x $top.selbgbut $top.selbgsep -sticky w
+    lappend pages [prefspage_general $notebook] [mc "General"]
+    lappend pages [prefspage_colors $notebook] [mc "Colors"]
+    lappend pages [prefspage_fonts $notebook] [mc "Fonts"]
+    foreach {page title} $pages {
+	if {$use_notebook} {
+	    $notebook add $page -text $title
+	} else {
+	    set btn [${NS}::button $notebook.b_[string map {. X} $page] \
+			 -text $title -command [list raise $page]]
+	    $page configure -text $title
+	    grid $btn -row 0 -column [incr col] -sticky w
+	    grid $page -row 1 -column 0 -sticky news -columnspan 100
+	}
+    }
 
-    ${NS}::label $top.cfont -text [mc "Fonts: press to choose"]
-    grid $top.cfont - -sticky w -pady 10
-    mkfontdisp mainfont $top [mc "Main font"]
-    mkfontdisp textfont $top [mc "Diff display font"]
-    mkfontdisp uifont $top [mc "User interface font"]
+    if {!$use_notebook} {
+	grid columnconfigure $notebook 0 -weight 1
+	grid rowconfigure $notebook 1 -weight 1
+	raise [lindex $pages 0]
+    }
+
+    grid $notebook -sticky news -padx 2 -pady 2
+    grid rowconfigure $top 0 -weight 1
+    grid columnconfigure $top 0 -weight 1
 
     ${NS}::frame $top.buts
     ${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active
@@ -10936,7 +11000,7 @@ proc doprefs {} {
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
     grid $top.buts - - -pady 10 -sticky ew
     grid columnconfigure $top 2 -weight 1
-    bind $top  "focus $top.buts.ok"
+    bind $top  [list focus $top.buts.ok]
 }
 
 proc choose_extdiff {} {

From 496c8ce6679d96a6b7653286b907fd420b51bbad Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Mon, 30 Jan 2012 23:38:42 +0000
Subject: [PATCH 3094/3720] gitk: fix setting font display with new tabbed
 dialog layout.

The changes to the dialog window tree broke the preview of the selected
font on the button. This corrects that issue.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index dcae0a7547..a62f25d549 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10751,7 +10751,7 @@ proc fontok {} {
     if {$fontparam(slant) eq "italic"} {
 	lappend fontpref($f) "italic"
     }
-    set w $prefstop.$f
+    set w $prefstop.notebook.fonts.$f
     $w conf -text $fontparam(family) -font $fontpref($f)
 
     fontcan

From 652c248dba4c5ff6fa68799c613757d632201869 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 3 Feb 2012 00:12:04 -0600
Subject: [PATCH 3095/3720] Teach 'git remote' that the config var
 branch.*.rebase can be 'interactive'

Signed-off-by: Johannes Schindelin 
---
 builtin/remote.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index fec92bc66e..7b37a23d97 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -253,7 +253,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	int rebase;
+	enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
 };
 
 static struct string_list branch_list;
@@ -310,7 +310,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			}
 			string_list_append(&info->merge, xstrdup(value));
 		} else
-			info->rebase = git_config_bool(orig_key, value);
+			info->rebase = value && *value == 'i' ?
+				INTERACTIVE_REBASE :
+				(git_config_bool(orig_key, value) ?
+				 NORMAL_REBASE : NO_REBASE);
 	}
 	return 0;
 }
@@ -994,7 +997,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf("rebases onto remote %s\n", merge->items[0].string);
+		printf("rebases %sonto remote %s\n",
+			branch_info->rebase == INTERACTIVE_REBASE ?
+			"interactively " : "", merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf(" merges with remote %s\n", merge->items[0].string);

From 000e1f111d44d8cc397c491a84104066128b86b2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:28:37 +0100
Subject: [PATCH 3096/3720] git-gui: fix encoding in git-gui file browser

Assume git tree objects (i.e. output of git-ls-tree) are encoded in system
encoding, for display in the git-gui file browser.

Signed-off-by: Karsten Blees 
---
 git-gui/lib/browser.tcl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 0328338fda..4fca8fb13c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary -encoding binary
+	fconfigure $fd -blocking 0 -translation binary
 	fileevent $fd readable [cb _read $fd]
 }
 

From 584ed9fd86e381e96da240865a19db5c1f751e15 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:38:07 +0100
Subject: [PATCH 3097/3720] gitk: fix file name encoding in diff hunk headers

Decode file names from system encoding in all diff hunk header lines, not
just the first (i.e. print nice file names in 'rename from' / 'rename to' /
'Binary files' lines, too).

Signed-off-by: Karsten Blees 
---
 gitk-git/gitk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index a62f25d549..3660096db5 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7811,6 +7811,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
+	    set line [encoding convertfrom $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {

From 142100b1375935fa89ae032cde0f137fa3eb2628 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 19:06:41 +0100
Subject: [PATCH 3098/3720] Revert "Windows: teach getenv to do a
 case-sensitive search"

This reverts commit df599e9612788b728ce43a03159b85f1fe624d6a.

As of 5e9637c6 "i18n: add infrastructure for translating Git with gettext",
eval_gettext uses MinGW envsubst.exe instead of git-sh-i18n--envsubst.exe
for variable substitution. This breaks git-submodule.sh messages and tests,
as envsubst.exe doesn't support case-sensitive environment lookup (the same
is true for almost everything on Windows, including MSys and Cygwin tools).

30a615ac "Windows/i18n: rename $path to prevent clashes with $PATH" renames
the conflicting variable in git-submodule.sh, so that it works on Windows
(i.e. with case-insensitive environment, regardless of the toolset).

Revert to the documented behaviour of case-insensitive environment on
Windows.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 116d214f7c..335965b290 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1183,31 +1183,14 @@ char **make_augmented_environ(const char *const *vars)
 }
 
 #undef getenv
-
-/*
- * The system's getenv looks up the name in a case-insensitive manner.
- * This version tries a case-sensitive lookup and falls back to
- * case-insensitive if nothing was found.  This is necessary because,
- * as a prominent example, CMD sets 'Path', but not 'PATH'.
- * Warning: not thread-safe.
- */
-static char *getenv_cs(const char *name)
-{
-	size_t len = strlen(name);
-	int i = lookup_env(environ, name, len);
-	if (i >= 0)
-		return environ[i] + len + 1;	/* skip past name and '=' */
-	return getenv(name);
-}
-
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv_cs(name);
+	char *result = getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv_cs("TMP");
+		result = getenv("TMP");
 		if (!result)
-			result = getenv_cs("TEMP");
+			result = getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */

From d8cd2ec6e3e5fcbee7d14d0d311686dfdbf275e2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:19:31 +0100
Subject: [PATCH 3099/3720] Revert "mingw.c: move definition of mingw_getenv
 down"

This reverts commit 06bc4b796ad69ba93f0a8c451368602e0553c2d3.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 335965b290..803a2506ff 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -180,7 +180,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	vsnprintf(question, sizeof(question), format, args);
 	va_end(args);
 
-	if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
+	if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
 		retry_hook[1] = question;
 		return !run_command_v_opt(retry_hook, 0);
 	}
@@ -666,6 +666,23 @@ char *mingw_getcwd(char *pointer, int len)
 	return ret;
 }
 
+#undef getenv
+char *mingw_getenv(const char *name)
+{
+	char *result = getenv(name);
+	if (!result && !strcmp(name, "TMPDIR")) {
+		/* on Windows it is TMP and TEMP */
+		result = getenv("TMP");
+		if (!result)
+			result = getenv("TEMP");
+	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
+	return result;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -765,7 +782,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-	char *p, **path, *envpath = mingw_getenv("PATH");
+	char *p, **path, *envpath = getenv("PATH");
 	int i, n = 0;
 
 	if (!envpath || !*envpath)
@@ -1182,23 +1199,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-	char *result = getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
-		if (!result)
-			result = getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 02de8e70e6b03b254f1f51fad6c14c05637f19cb Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:24:19 +0100
Subject: [PATCH 3100/3720] Win32: Thread-safe windows console output

Winansi.c has many static variables that are accessed and modified from
the [v][f]printf / fputs functions overridden in the file. This may cause
multi threaded git commands that print to the console to produce corrupted
output or even crash.

Additionally, winansi.c doesn't override all functions that can be used to
print to the console (e.g. fwrite, write, fputc are missing), so that ANSI
escapes don't work properly for some git commands (e.g. git-grep).

Instead of doing ANSI emulation in just a few wrapped functions on top of
the IO API, let's plug into the IO system and take advantage of the thread
safety inherent to the IO system.

Redirect stdout and stderr to a pipe if they point to the console. A
background thread reads from the pipe, handles ANSI escape sequences and
UTF-8 to UTF-16 conversion, then writes to the console.

The pipe-based stdout and stderr replacements must be set to unbuffered, as
MSVCRT doesn't support line buffering and fully buffered streams are
inappropriate for console output.

Due to the byte-oriented pipe, ANSI escape sequences and multi-byte UTF-8
sequences can no longer be expected to arrive in one piece. Replace the
string-based ansi_emulate() with a simple stateful parser (this also fixes
colored diff hunk headers, which were broken as of commit 2efcc977).

Override isatty to return true for the pipes redirecting to the console.

Exec/spawn obtain the original console handle to pass to the next process
via winansi_get_osfhandle().

All other overrides are gone, the default stdio implementations work as
expected with the piped stdout/stderr descriptors.

Global variables are either initialized on startup (single threaded) or
exclusively modified by the background thread. Threads communicate through
the pipe, no further synchronization is necessary.

The background thread is terminated by disonnecting the pipe after flushing
the stdio and pipe buffers. This doesn't work for anonymous pipes (created
via CreatePipe), as DisconnectNamedPipe only works on the read end, which
discards remaining data. Thus we have to setup the pipe manually, with the
write end beeing the server (opened with CreateNamedPipe) and the read end
the client (opened with CreateFile).

Limitations: doesn't track reopened or duped file descriptors, i.e.:
- fdopen(1/2) returns fully buffered streams
- dup(1/2), dup2(1/2) returns normal pipe descriptors (i.e. isatty() =
  false, winansi_get_osfhandle won't return the original console handle)

Currently, only the git-format-patch command uses xfdopen(xdup(1)) (see
"realstdout" in builtin/log.c), but works well with these limitations.

Many thanks to Atsushi Nakagawa  for suggesting and
reviewing the thread-exit-mechanism.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c   |   9 +-
 compat/mingw.h   |  12 +-
 compat/winansi.c | 420 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 282 insertions(+), 159 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 803a2506ff..62c63effd9 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -918,9 +918,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	memset(&si, 0, sizeof(si));
 	si.cb = sizeof(si);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-	si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-	si.hStdError = (HANDLE) _get_osfhandle(fherr);
+	si.hStdInput = winansi_get_osfhandle(fhin);
+	si.hStdOutput = winansi_get_osfhandle(fhout);
+	si.hStdError = winansi_get_osfhandle(fherr);
 
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
@@ -1879,4 +1879,7 @@ void mingw_startup()
 	_setmode(_fileno(stdin), _O_BINARY);
 	_setmode(_fileno(stdout), _O_BINARY);
 	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
 }
diff --git a/compat/mingw.h b/compat/mingw.h
index 407bad231b..2683adcaf7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -288,14 +288,10 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-int winansi_vfprintf(FILE *stream, const char *format, va_list list);
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
-#define vfprintf winansi_vfprintf
+void winansi_init(void);
+int winansi_isatty(int fd);
+HANDLE winansi_get_osfhandle(int fd);
+#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index bec6713b74..a3e4d88295 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,18 +4,13 @@
 
 #undef NOGDI
 #include "../git-compat-util.h"
-#include 
 #include 
 #include 
 
 /*
  Functions to be wrapped:
 */
-#undef printf
-#undef fprintf
-#undef fputs
-#undef vfprintf
-/* TODO: write */
+#undef isatty
 
 /*
  ANSI codes used by git: m, K
@@ -28,7 +23,10 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
-static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hwrite1 = INVALID_HANDLE_VALUE, hwrite2 = INVALID_HANDLE_VALUE;
+static HANDLE hconsole1, hconsole2;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -44,27 +42,19 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void print_font_warning(void)
+static void warn_if_raster_font(void)
 {
-	warning("Your console font probably doesn\'t support Unicode. If "
-		"you experience strange characters in the output, consider "
-		"switching to a TrueType font such as Lucida Console!");
-}
-
-static void check_truetype_font(void)
-{
-	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't do this twice */
-	if (truetype_font_checked)
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
 		return;
-	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
+			GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);
@@ -73,8 +63,8 @@ static void check_truetype_font(void)
 	} else {
 		/* pre-Vista: check default console font in registry */
 		HKEY hkey;
-		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
-				KEY_READ, &hkey)) {
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+				0, KEY_READ, &hkey)) {
 			DWORD size = sizeof(fontFamily);
 			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
 					(LPVOID) &fontFamily, &size);
@@ -82,61 +72,63 @@ static void check_truetype_font(void)
 		}
 	}
 
-	if (!(fontFamily & TMPF_TRUETYPE))
-		atexit(print_font_warning);
+	if (!(fontFamily & TMPF_TRUETYPE)) {
+		const wchar_t *msg = L"\nWarning: Your console font probably "
+			L"doesn\'t support Unicode. If you experience strange "
+			L"characters in the output, consider switching to a "
+			L"TrueType font such as Lucida Console!\n";
+		WriteConsoleW(console, msg, wcslen(msg), NULL, NULL);
+	}
 }
 
-static int is_console(FILE *stream)
+static int is_console(int fd)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
 	HANDLE hcon;
 
 	static int initialized = 0;
 
-	/* use cached value if stream hasn't changed */
-	if (stream == last_stream)
-		return console != NULL;
-
-	last_stream = stream;
-	console = NULL;
-
-	/* get OS handle of the stream */
-	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	/* get OS handle of the file descriptor */
+	hcon = (HANDLE) _get_osfhandle(fd);
 	if (hcon == INVALID_HANDLE_VALUE)
 		return 0;
 
+	/* check if its a device (i.e. console, printer, serial port) */
+	if (GetFileType(hcon) != FILE_TYPE_CHAR)
+		return 0;
+
 	/* check if its a handle to a console output screen buffer */
 	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
+	/* initialize attributes */
 	if (!initialized) {
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
 	}
 
-	console = hcon;
 	return 1;
 }
 
-static int write_console(const char *str, size_t len)
-{
-	/* convert utf-8 to utf-16, write directly to console */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
-	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
-	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
 
+static void write_console(unsigned char *str, size_t len)
+{
+	/* only called from console_thread, so a static buffer will do */
+	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+
+	/* convert utf-8 to utf-16 */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
+			ARRAY_SIZE(wbuf));
+
+	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/*
-	 * if non-ascii characters are printed, check that the current console
-	 * font supports this
-	 */
+	/* remember if non-ascii characters are printed */
 	if (wlen != len)
-		check_truetype_font();
-
-	/* return original (utf-8 encoded) length */
-	return len;
+		non_ascii_used = 1;
 }
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
@@ -182,18 +174,13 @@ static void erase_in_line(void)
 		&dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-	const char *func;
-	size_t len = strspn(str, "0123456789;");
-	func = str + len;
-
-	switch (*func) {
+	int i;
+	switch (func) {
 	case 'm':
-		do {
-			long val = strtol(str, (char **)&str, 10);
-			switch (val) {
+		for (i = 0; i < paramlen; i++) {
+			switch (params[i]) {
 			case 0: /* reset */
 				attr = plain_attr;
 				negative = 0;
@@ -316,9 +303,7 @@ static const char *set_attr(const char *str)
 				/* Unsupported code */
 				break;
 			}
-			str++;
-		} while (*(str-1) == ';');
-
+		}
 		set_console_attr();
 		break;
 	case 'K':
@@ -328,112 +313,251 @@ static const char *set_attr(const char *str)
 		/* Unsupported code */
 		break;
 	}
-
-	return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+	TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-	int rv = 0;
-	const char *pos = str;
+	unsigned char buffer[BUFFER_SIZE];
+	DWORD bytes;
+	int start, end = 0, c, parampos = 0, state = TEXT;
+	int params[MAX_PARAMS];
 
-	fflush(stream);
+	while (1) {
+		/* read next chunk of bytes from the pipe */
+		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+				NULL)) {
+			/* exit if pipe has been closed or disconnected */
+			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+					GetLastError() == ERROR_BROKEN_PIPE)
+				break;
+			/* ignore other errors */
+			continue;
+		}
 
-	while (*pos) {
-		pos = strstr(str, "\033[");
-		if (pos) {
-			size_t len = pos - str;
+		/* scan the bytes and handle ANSI control codes */
+		bytes += end;
+		start = end = 0;
+		while (end < bytes) {
+			c = buffer[end++];
+			switch (state) {
+			case TEXT:
+				if (c == ESCAPE) {
+					/* print text seen so far */
+					if (end - 1 > start)
+						write_console(buffer + start,
+							end - 1 - start);
 
-			if (len) {
-				size_t out_len = write_console(str, len);
-				rv += out_len;
-				if (out_len < len)
-					return rv;
+					/* then start parsing escape sequence */
+					start = end - 1;
+					memset(params, 0, sizeof(params));
+					parampos = 0;
+					state = ESCAPE;
+				}
+				break;
+
+			case ESCAPE:
+				/* continue if "\033[", otherwise bail out */
+				state = (c == BRACKET) ? BRACKET : TEXT;
+				break;
+
+			case BRACKET:
+				/* parse [0-9;]* into array of parameters */
+				if (c >= '0' && c <= '9') {
+					params[parampos] *= 10;
+					params[parampos] += c - '0';
+				} else if (c == ';') {
+					/*
+					 * next parameter, bail out if out of
+					 * bounds
+					 */
+					parampos++;
+					if (parampos >= MAX_PARAMS)
+						state = TEXT;
+				} else {
+					/*
+					 * end of escape sequence, change
+					 * console attributes
+					 */
+					set_attr(c, params, parampos + 1);
+					start = end;
+					state = TEXT;
+				}
+				break;
+			}
+		}
+
+		/* print remaining text unless parsing an escape sequence */
+		if (state == TEXT && end > start) {
+			/* check for incomplete UTF-8 sequences and fix end */
+			if (buffer[end - 1] >= 0x80) {
+				if (buffer[end -1] >= 0xc0)
+					end--;
+				else if (end - 1 > start &&
+						buffer[end - 2] >= 0xe0)
+					end -= 2;
+				else if (end - 2 > start &&
+						buffer[end - 3] >= 0xf0)
+					end -= 3;
 			}
 
-			str = pos + 2;
-			rv += 2;
+			/* print remaining complete UTF-8 sequences */
+			if (end > start)
+				write_console(buffer + start, end - start);
 
-			pos = set_attr(str);
-			rv += pos - str;
-			str = pos;
+			/* move remaining bytes to the front */
+			if (end < bytes)
+				memmove(buffer, buffer + end, bytes - end);
+			end = bytes - end;
 		} else {
-			size_t len = strlen(str);
-			rv += write_console(str, len);
-			return rv;
+			/* all data has been consumed, mark buffer empty */
+			end = 0;
 		}
 	}
-	return rv;
+
+	/* check if the console font supports unicode */
+	warn_if_raster_font();
+
+	CloseHandle(hread);
+	return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-	int rv;
+	/* flush all streams */
+	_flushall();
 
-	if (!is_console(stream))
-		return fputs(str, stream);
+	/* signal console thread to exit */
+	FlushFileBuffers(hwrite);
+	DisconnectNamedPipe(hwrite);
 
-	rv = ansi_emulate(str, stream);
+	/* wait for console thread to copy remaining data */
+	WaitForSingleObject(hthread, INFINITE);
 
-	if (rv >= 0)
-		return 0;
+	/* cleanup handles... */
+	if (hwrite1 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite1);
+	if (hwrite2 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite2);
+	CloseHandle(hwrite);
+	CloseHandle(hthread);
+}
+
+static void die_lasterr(const char *fmt, ...)
+{
+	va_list params;
+	va_start(params, fmt);
+	errno = err_win_to_posix(GetLastError());
+	die_errno(fmt, params);
+	va_end(params);
+}
+
+static HANDLE duplicate_handle(HANDLE hnd)
+{
+	HANDLE hresult, hproc = GetCurrentProcess();
+	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+			DUPLICATE_SAME_ACCESS))
+		die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+	return hresult;
+}
+
+static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+{
+	/* get original console handle */
+	int fd = _fileno(stream);
+	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
+	if (hcon == INVALID_HANDLE_VALUE)
+		die_errno("_get_osfhandle(%i) failed", fd);
+
+	/* save a copy to phcon and console (used by the background thread) */
+	console = *phcon = duplicate_handle(hcon);
+
+	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
+	if (_dup2(new_fd, fd))
+		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+
+	/* no buffering, or stdout / stderr will be out of sync */
+	setbuf(stream, NULL);
+	return (HANDLE) _get_osfhandle(fd);
+}
+
+void winansi_init(void)
+{
+	int con1, con2, hwrite_fd;
+	char name[32];
+
+	/* check if either stdout or stderr is a console output screen buffer */
+	con1 = is_console(1);
+	con2 = is_console(2);
+	if (!con1 && !con2)
+		return;
+
+	/* create a named pipe to communicate with the console thread */
+	sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+	hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+	if (hwrite == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateNamedPipe failed");
+
+	hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (hread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateFile for named pipe failed");
+
+	/* start console spool thread on the pipe's read end */
+	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+	if (hthread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateThread(console_thread) failed");
+
+	/* schedule cleanup routine */
+	if (atexit(winansi_exit))
+		die_errno("atexit(winansi_exit) failed");
+
+	/* create a file descriptor for the write end of the pipe */
+	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
+	if (hwrite_fd == -1)
+		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
+
+	/* redirect stdout / stderr to the pipe */
+	if (con1)
+		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+	if (con2)
+		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
+
+	/* close pipe file descriptor (also closes the duped hwrite) */
+	close(hwrite_fd);
+}
+
+static int is_same_handle(HANDLE hnd, int fd)
+{
+	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
+}
+
+/*
+ * Return true if stdout / stderr is a pipe redirecting to the console.
+ */
+int winansi_isatty(int fd)
+{
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return 1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return 1;
 	else
-		return EOF;
+		return isatty(fd);
 }
 
-int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-	int len, rv;
-	char small_buf[256];
-	char *buf = small_buf;
-	va_list cp;
-
-	if (!is_console(stream))
-		goto abort;
-
-	va_copy(cp, list);
-	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-	va_end(cp);
-
-	if (len > sizeof(small_buf) - 1) {
-		buf = malloc(len + 1);
-		if (!buf)
-			goto abort;
-
-		len = vsnprintf(buf, len + 1, format, list);
-	}
-
-	rv = ansi_emulate(buf, stream);
-
-	if (buf != small_buf)
-		free(buf);
-	return rv;
-
-abort:
-	rv = vfprintf(stream, format, list);
-	return rv;
-}
-
-int winansi_fprintf(FILE *stream, const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stream, format, list);
-	va_end(list);
-
-	return rv;
-}
-
-int winansi_printf(const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stdout, format, list);
-	va_end(list);
-
-	return rv;
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return hconsole1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return hconsole2;
+	else
+		return (HANDLE) _get_osfhandle(fd);
 }

From 0067133f1bd6ee511cf4113a8e714f3fd41c0457 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:05:06 +0100
Subject: [PATCH 3101/3720] Win32: add Unicode conversion functions

Add Unicode conversion functions to convert between Windows native UTF-16LE
encoding to UTF-8 and back.

To support repositories with legacy-encoded file names, the UTF-8 to UTF-16
conversion function tries to create valid, unique file names even for
invalid UTF-8 byte sequences, so that these repositories can be checked out
without error.

The current implementation leaves invalid UTF-8 bytes in range 0xa0 - 0xff
as is (producing printable Unicode chars \u00a0 - \u00ff, equivalent to
ISO-8859-1), and converts 0x80 - 0x9f to hex-code (\u0080 - \u009f are
control chars).

The Windows MultiByteToWideChar API was not used as it either drops invalid
UTF-8 sequences (on Win2k/XP; producing non-unique or even empty file
names) or converts them to the replacement char \ufffd (Vista/7; causing
ERROR_INVALID_NAME in subsequent calls to file system APIs).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c |  85 ++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 62c63effd9..be20d37ef7 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1860,6 +1860,91 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
diff --git a/compat/mingw.h b/compat/mingw.h
index 2683adcaf7..ddb228473b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -326,6 +326,110 @@ void mingw_mark_as_git_dir(const char *dir);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A replacement of main() that adds win32 specific initialization.
  */

From 6c578b77e5d8e38150b6f8a94ce17d6c11af7934 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 21:28:22 +0100
Subject: [PATCH 3102/3720] Win32: Unicode file name support (except dirent)

Replaces Windows "ANSI" APIs dealing with file- or path names with their
Unicode equivalent, adding UTF-8/UTF-16LE conversion as necessary.

The dirent API (opendir/readdir/closedir) is updated in a separate commit.

Adds trivial wrappers for access, chmod and chdir.

Adds wrapper for mktemp (needed for both mkstemp and mkdtemp).

The simplest way to convert a repository with legacy-encoded (e.g. Cp1252)
file names to UTF-8 ist to checkout with an old msysgit version and
"git add --all & git commit" with the new version.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 202 ++++++++++++++++++++++++++++++++++---------------
 compat/mingw.h |  13 ++++
 2 files changed, 155 insertions(+), 60 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index be20d37ef7..80ba4e3364 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "win32.h"
 #include 
+#include 
 #include "../strbuf.h"
 #include "../run-command.h"
 #include "../cache.h"
@@ -200,14 +201,16 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	}
 }
 
-#undef unlink
 int mingw_unlink(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
 	/* read-only files cannot be removed */
-	chmod(pathname, 0666);
-	while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
 		/*
@@ -223,22 +226,20 @@ int mingw_unlink(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = unlink(pathname);
+	       ret = _wunlink(wpathname);
 	return ret;
 }
 
-static int is_dir_empty(const char *path)
+static int is_dir_empty(const wchar_t *wpath)
 {
-	struct strbuf buf = STRBUF_INIT;
-	WIN32_FIND_DATAA findbuf;
+	WIN32_FIND_DATAW findbuf;
 	HANDLE handle;
-
-	strbuf_addf(&buf, "%s\\*", path);
-	handle = FindFirstFileA(buf.buf, &findbuf);
-	if (handle == INVALID_HANDLE_VALUE) {
-		strbuf_release(&buf);
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
 		return GetLastError() == ERROR_NO_MORE_FILES;
-	}
 
 	while (!wcscmp(findbuf.cFileName, L".") ||
 			!wcscmp(findbuf.cFileName, L".."))
@@ -248,19 +249,20 @@ static int is_dir_empty(const char *path)
 			return err == ERROR_NO_MORE_FILES;
 		}
 	FindClose(handle);
-	strbuf_release(&buf);
 	return 0;
 }
 
-#undef rmdir
 int mingw_rmdir(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
-	while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
-		if (!is_dir_empty(pathname)) {
+		if (!is_dir_empty(wpathname)) {
 			errno = ENOTEMPTY;
 			break;
 		}
@@ -277,14 +279,14 @@ int mingw_rmdir(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = rmdir(pathname);
+	       ret = _wrmdir(wpathname);
 	return ret;
 }
 
-static int make_hidden(const char *path)
+static int make_hidden(const wchar_t *path)
 {
-	DWORD attribs = GetFileAttributes(path);
-	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+	DWORD attribs = GetFileAttributesW(path);
+	if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
 		return 0;
 	errno = err_win_to_posix(GetLastError());
 	return -1;
@@ -292,19 +294,23 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
-	    make_hidden(dir))
-		warning("Failed to make '%s' hidden", dir);
+	wchar_t wdir[MAX_PATH];
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
+		if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
+			warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
 		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
 		 "dotGitOnly" : "true"));
 }
 
-#undef mkdir
 int mingw_mkdir(const char *path, int mode)
 {
-	int ret = mkdir(path);
+	int ret;
+	wchar_t wpath[MAX_PATH];
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
 	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
 		/*
 		 * In Windows a file or dir starting with a dot is not
@@ -313,17 +319,17 @@ int mingw_mkdir(const char *path, int mode)
 		 */
 		const char *start = basename((char*)path);
 		if (*start == '.')
-			return make_hidden(path);
+			return make_hidden(wpath);
 	}
 	return ret;
 }
 
-#undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
 	va_list args;
 	unsigned mode;
 	int fd;
+	wchar_t wfilename[MAX_PATH];
 
 	va_start(args, oflags);
 	mode = va_arg(args, int);
@@ -332,10 +338,12 @@ int mingw_open (const char *filename, int oflags, ...)
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
 
-	fd = open(filename, oflags, mode);
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	fd = _wopen(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
-		DWORD attrs = GetFileAttributes(filename);
+		DWORD attrs = GetFileAttributesW(wfilename);
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
@@ -347,7 +355,7 @@ int mingw_open (const char *filename, int oflags, ...)
 		 * such a file is created.
 		 */
 		const char *start = basename((char*)filename);
-		if (*start == '.' && make_hidden(filename))
+		if (*start == '.' && make_hidden(wfilename))
 			warning("Could not mark '%s' as hidden.", filename);
 	}
 	return fd;
@@ -370,38 +378,69 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 	return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
-#undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = fopen(filename, otype);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfopen(wfilename, wotype);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
-#undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = freopen(filename, otype, stream);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -427,10 +466,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
  */
 static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
-	int err;
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
-	if (!(err = get_file_attr(file_name, &fdata))) {
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
 		buf->st_ino = 0;
 		buf->st_gid = 0;
 		buf->st_uid = 0;
@@ -443,8 +484,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-			WIN32_FIND_DATAA findbuf;
-			HANDLE handle = FindFirstFileA(file_name, &findbuf);
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
 			if (handle != INVALID_HANDLE_VALUE) {
 				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
 						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
@@ -463,7 +504,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		}
 		return 0;
 	}
-	errno = err;
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	default:
+		errno = ENOENT;
+		break;
+	}
 	return -1;
 }
 
@@ -552,16 +609,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
 {
 	FILETIME mft, aft;
 	int fh, rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
 	/* must have write permission */
-	DWORD attrs = GetFileAttributes(file_name);
+	attrs = GetFileAttributesW(wfilename);
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors here; open() will report them */
-		SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
 	}
 
-	if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+	if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
 		rc = -1;
 		goto revert_attrs;
 	}
@@ -584,7 +645,7 @@ revert_attrs:
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors again */
-		SetFileAttributes(file_name, attrs);
+		SetFileAttributesW(wfilename, attrs);
 	}
 	return rc;
 }
@@ -595,6 +656,18 @@ unsigned int sleep (unsigned int seconds)
 	return 0;
 }
 
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
 int mkstemp(char *template)
 {
 	char *filename = mktemp(template);
@@ -653,17 +726,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
 	return result;
 }
 
-#undef getcwd
 char *mingw_getcwd(char *pointer, int len)
 {
 	int i;
-	char *ret = getcwd(pointer, len);
-	if (!ret)
-		return ret;
+	wchar_t wpointer[MAX_PATH];
+	if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+		return NULL;
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
 	for (i = 0; pointer[i]; i++)
 		if (pointer[i] == '\\')
 			pointer[i] = '/';
-	return ret;
+	return pointer;
 }
 
 #undef getenv
@@ -1496,33 +1570,36 @@ int mingw_rename(const char *pold, const char *pnew)
 {
 	DWORD attrs, gle;
 	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+		return -1;
 
 	/*
 	 * Try native rename() first to get errno right.
 	 * It is based on MoveFile(), which cannot overwrite existing files.
 	 */
-	if (!rename(pold, pnew))
+	if (!_wrename(wpold, wpnew))
 		return 0;
 	if (errno != EEXIST)
 		return -1;
 repeat:
-	if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 		return 0;
 	/* TODO: translate more errors */
 	gle = GetLastError();
 	if (gle == ERROR_ACCESS_DENIED &&
-	    (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
 		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
 			errno = EISDIR;
 			return -1;
 		}
 		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
-		    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
-			if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 				return 0;
 			gle = GetLastError();
 			/* revert file attributes on failure */
-			SetFileAttributes(pnew, attrs);
+			SetFileAttributesW(wpnew, attrs);
 		}
 	}
 	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
@@ -1732,11 +1809,16 @@ void mingw_open_html(const char *unixpath)
 
 int link(const char *oldpath, const char *newpath)
 {
-	typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+	typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
 	static T create_hard_link = NULL;
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
 	if (!create_hard_link) {
 		create_hard_link = (T) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+			GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
 		if (!create_hard_link)
 			create_hard_link = (T)-1;
 	}
@@ -1744,7 +1826,7 @@ int link(const char *oldpath, const char *newpath)
 		errno = ENOSYS;
 		return -1;
 	}
-	if (!create_hard_link(newpath, oldpath, NULL)) {
+	if (!create_hard_link(wnewpath, woldpath, NULL)) {
 		errno = err_win_to_posix(GetLastError());
 		return -1;
 	}
diff --git a/compat/mingw.h b/compat/mingw.h
index ddb228473b..ea8c1f8993 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -182,6 +182,19 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 

From 03011a3b53faa7881aa038b179d46ea3f9c510b5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:01:09 +0100
Subject: [PATCH 3103/3720] Win32: Unicode file name support (dirent)

Changes opendir/readdir to use Windows Unicode APIs and convert between
UTF-8/UTF-16.

Removes parameter checks that are already covered by xutftowcs_path. This
changes detection of ENAMETOOLONG from MAX_PATH - 2 to MAX_PATH (matching
is_dir_empty in mingw.c). If name + "/*" or the resulting absolute path is
too long, FindFirstFile fails and errno is set through err_win_to_posix.

Increases the size of dirent.d_name to accommodate the full
WIN32_FIND_DATA.cFileName converted to UTF-8 (UTF-16 to UTF-8 conversion
may grow by factor three in the worst case).

Signed-off-by: Karsten Blees 
---
 compat/win32/dirent.c | 30 ++++++++++--------------------
 compat/win32/dirent.h |  2 +-
 2 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 82a515c21b..52420ec7d4 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -6,10 +6,10 @@ struct DIR {
 	int dd_stat;          /* 0-based index */
 };
 
-static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
 {
-	/* copy file name from WIN32_FIND_DATA to dirent */
-	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+	/* convert UTF-16 name to UTF-8 */
+	xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
 
 	/* Set file type, based on WIN32_FIND_DATA */
 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -20,25 +20,15 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
 
 DIR *opendir(const char *name)
 {
-	char pattern[MAX_PATH];
-	WIN32_FIND_DATAA fdata;
+	wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
+	WIN32_FIND_DATAW fdata;
 	HANDLE h;
 	int len;
 	DIR *dir;
 
-	/* check that name is not NULL */
-	if (!name) {
-		errno = EINVAL;
+	/* convert name to UTF-16 and check length < MAX_PATH */
+	if ((len = xutftowcs_path(pattern, name)) < 0)
 		return NULL;
-	}
-	/* check that the pattern won't be too long for FindFirstFileA */
-	len = strlen(name);
-	if (len + 2 >= MAX_PATH) {
-		errno = ENAMETOOLONG;
-		return NULL;
-	}
-	/* copy name to temp buffer */
-	memcpy(pattern, name, len + 1);
 
 	/* append optional '/' and wildcard '*' */
 	if (len && !is_dir_sep(pattern[len - 1]))
@@ -47,7 +37,7 @@ DIR *opendir(const char *name)
 	pattern[len] = 0;
 
 	/* open find handle */
-	h = FindFirstFileA(pattern, &fdata);
+	h = FindFirstFileW(pattern, &fdata);
 	if (h == INVALID_HANDLE_VALUE) {
 		DWORD err = GetLastError();
 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
@@ -72,8 +62,8 @@ struct dirent *readdir(DIR *dir)
 	/* if first entry, dirent has already been set up by opendir */
 	if (dir->dd_stat) {
 		/* get next entry and convert from WIN32_FIND_DATA to dirent */
-		WIN32_FIND_DATAA fdata;
-		if (FindNextFileA(dir->dd_handle, &fdata)) {
+		WIN32_FIND_DATAW fdata;
+		if (FindNextFileW(dir->dd_handle, &fdata)) {
 			finddata2dirent(&dir->dd_dir, &fdata);
 		} else {
 			DWORD lasterr = GetLastError();
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 8838cd61fc..058207e4bf 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,7 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
-	char d_name[MAX_PATH];     /* file name */
+	char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
 };
 
 DIR *opendir(const char *dirname);

From 6a062f746edae79f12f6461782a5c8de0c580fb1 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 4 Feb 2012 21:54:36 +0100
Subject: [PATCH 3104/3720] Unicode file name support (gitk and git-gui)

Assumes file names in git tree objects are UTF-8 encoded.

On most unix systems, the system encoding (and thus the TCL system
encoding) will be UTF-8, so file names will be displayed correctly.

On Windows, it is impossible to set the system encoding to UTF-8. Changing
the TCL system encoding (via 'encoding system ...', e.g. in the startup
code) is explicitly discouraged by the TCL docs.

Change gitk and git-gui functions dealing with file names to always convert
from and to UTF-8.

Signed-off-by: Karsten Blees 
---
 git-gui/git-gui.sh      | 11 +++++++----
 git-gui/lib/browser.tcl |  2 +-
 git-gui/lib/index.tcl   |  6 +++---
 gitk-git/gitk           | 16 ++++++++--------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index a59020bcc5..e5038ddd12 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -533,6 +533,9 @@ proc git {args} {
 
 	_trace_exec [concat $opt $cmdp $args]
 	set result [eval exec $opt $cmdp $args]
+	if {[encoding system] != "utf-8"} {
+		set result [encoding convertfrom utf-8 [encoding convertto $result]]
+	}
 	if {$::_trace} {
 		puts stderr "< $result"
 	}
@@ -1087,7 +1090,7 @@ git-version proc _parse_config {arr_name args} {
 				[list git_read config] \
 				$args \
 				[list --null --list]]
-			fconfigure $fd_rc -translation binary
+			fconfigure $fd_rc -translation binary -encoding utf-8
 			set buf [read $fd_rc]
 			close $fd_rc
 		}
@@ -1652,7 +1655,7 @@ proc read_diff_index {fd after} {
 		set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			[lindex $i 4]? \
 			[list [lindex $i 0] [lindex $i 2]] \
 			[list]
@@ -1685,7 +1688,7 @@ proc read_diff_files {fd after} {
 		set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			?[lindex $i 4] \
 			[list] \
 			[list [lindex $i 0] [lindex $i 2]]
@@ -1708,7 +1711,7 @@ proc read_ls_others {fd after} {
 	set pck [split $buf_rlo "\0"]
 	set buf_rlo [lindex $pck end]
 	foreach p [lrange $pck 0 end-1] {
-		set p [encoding convertfrom $p]
+		set p [encoding convertfrom utf-8 $p]
 		if {[string index $p end] eq {/}} {
 			set p [string range $p 0 end-1]
 		}
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 4fca8fb13c..555db896f4 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary
+	fconfigure $fd -blocking 0 -translation binary -encoding utf-8
 	fileevent $fd readable [cb _read $fd]
 }
 
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdde21..6ca0a6e369 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -115,7 +115,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
 		set info [lindex $s 2]
 		if {$info eq {}} continue
 
-		puts -nonewline $fd "$info\t[encoding convertto $path]\0"
+		puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -186,7 +186,7 @@ proc write_update_index {fd pathList totalCnt batch after} {
 		?M {set new M_}
 		?? {continue}
 		}
-		puts -nonewline $fd "[encoding convertto $path]\0"
+		puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -247,7 +247,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
 		?M -
 		?T -
 		?D {
-			puts -nonewline $fd "[encoding convertto $path]\0"
+			puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 			display_file $path ?_
 		}
 		}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 3660096db5..f9e936d69e 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7288,7 +7288,7 @@ proc gettreeline {gtf id} {
 	if {[string index $fname 0] eq "\""} {
 	    set fname [lindex $fname 0]
 	}
-	set fname [encoding convertfrom $fname]
+	set fname [encoding convertfrom utf-8 $fname]
 	lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -7507,7 +7507,7 @@ proc gettreediffline {gdtf ids} {
 	    if {[string index $file 0] eq "\""} {
 		set file [lindex $file 0]
 	    }
-	    set file [encoding convertfrom $file]
+	    set file [encoding convertfrom utf-8 $file]
 	    if {$file ne [lindex $treediff end]} {
 		lappend treediff $file
 		lappend sublist $file
@@ -7656,7 +7656,7 @@ proc makediffhdr {fname ids} {
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -7690,7 +7690,7 @@ proc getblobdiffline {bdf ids} {
 	}
 	if {![string compare -length 5 "diff " $line]} {
 	    if {![regexp {^diff (--cc|--git) } $line m type]} {
-		set line [encoding convertfrom $line]
+		set line [encoding convertfrom utf-8 $line]
 		$ctext insert end "$line\n" hunksep
 		continue
 	    }
@@ -7737,7 +7737,7 @@ proc getblobdiffline {bdf ids} {
 	    makediffhdr $fname $ids
 
 	} elseif {![string compare -length 16 "* Unmerged path " $line]} {
-	    set fname [encoding convertfrom [string range $line 16 end]]
+	    set fname [encoding convertfrom utf-8 [string range $line 16 end]]
 	    $ctext insert end "\n"
 	    set curdiffstart [$ctext index "end - 1c"]
 	    lappend ctext_file_names $fname
@@ -7792,7 +7792,7 @@ proc getblobdiffline {bdf ids} {
 		if {[string index $fname 0] eq "\""} {
 		    set fname [lindex $fname 0]
 		}
-		set fname [encoding convertfrom $fname]
+		set fname [encoding convertfrom utf-8 $fname]
 		set i [lsearch -exact $treediffs($ids) $fname]
 		if {$i >= 0} {
 		    setinlist difffilestart $i $curdiffstart
@@ -7811,7 +7811,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
-	    set line [encoding convertfrom $line]
+	    set line [encoding convertfrom utf-8 $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {
@@ -11460,7 +11460,7 @@ proc cache_gitattr {attr pathlist} {
 	    foreach row [split $rlist "\n"] {
 		if {[regexp "(.*): $attr: (.*)" $row m path value]} {
 		    if {[string index $path 0] eq "\""} {
-			set path [encoding convertfrom [lindex $path 0]]
+			set path [encoding convertfrom utf-8 [lindex $path 0]]
 		    }
 		    set path_attr_cache($attr,$path) $value
 		}

From 4a099819968e7dfad66417f6887f190bf0b9d236 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:27:53 +0100
Subject: [PATCH 3105/3720] Win32: Unicode arguments (outgoing)

Convert command line arguments from UTF-8 to UTF-16 when creating other
processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 80ba4e3364..929c88e4e5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -958,9 +958,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFO si;
+	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
 	struct strbuf envblk, args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
 	unsigned flags;
 	BOOL ret;
 
@@ -996,6 +997,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	si.hStdOutput = winansi_get_osfhandle(fhout);
 	si.hStdError = winansi_get_osfhandle(fherr);
 
+	if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
 	if (prepend_cmd) {
@@ -1013,6 +1019,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			free(quoted);
 	}
 
+	wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
@@ -1034,12 +1044,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	}
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir, &si, &pi);
+	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
 	if (env)
 		strbuf_release(&envblk);
-	strbuf_release(&args);
+	free(wargs);
 
 	if (!ret) {
 		errno = ENOENT;

From 159d35dfe1f9e3b5645047dd1c6c8b12c83a2975 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:28:27 +0100
Subject: [PATCH 3106/3720] Win32: Unicode arguments (incoming)

Convert command line arguments from UTF-16 to UTF-8 on startup.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 929c88e4e5..c16f4bca75 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2043,10 +2043,41 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
  */
 int _CRT_glob = 0;
 
+typedef struct {
+	int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+		_startupinfo *si);
+
 void mingw_startup()
 {
-	/* copy executable name to argv[0] */
-	__argv[0] = xstrdup(_pgmptr);
+	int i, len, maxlen, argc;
+	char *buffer;
+	wchar_t **wenv, **wargv;
+	_startupinfo si;
+
+	/* get wide char arguments and environment */
+	si.newmode = 0;
+	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(_wpgmptr);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = xmalloc(maxlen);
+
+	/* convert command line arguments and environment to UTF-8 */
+	len = xwcstoutf(buffer, _wpgmptr, maxlen);
+	__argv[0] = xmemdupz(buffer, len);
+	for (i = 1; i < argc; i++) {
+		len = xwcstoutf(buffer, wargv[i], maxlen);
+		__argv[i] = xmemdupz(buffer, len);
+	}
+	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);

From b642d4a0f78a2c195d50e4acbcf3a3a1a7d70c51 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:17:49 +0100
Subject: [PATCH 3107/3720] Win32: sync Unicode console output and file system

Use the same Unicode conversion functions for file names and console
conversions so that the file system and console output are in sync when
checking out legacy encoded repositories (i.e. with invalid UTF-8 file
names).

Signed-off-by: Karsten Blees 
---
 compat/winansi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a3e4d88295..9f95954390 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -120,8 +120,7 @@ static void write_console(unsigned char *str, size_t len)
 	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
 
 	/* convert utf-8 to utf-16 */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
-			ARRAY_SIZE(wbuf));
+	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);

From 1bced4d89e03d3e60c707e9ed71bd708f7a19df8 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:07:46 +0100
Subject: [PATCH 3108/3720] Win32: Unicode environment (outgoing)

Convert environment from UTF-8 to UTF-16 when creating other processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index c16f4bca75..0422100eab 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -960,9 +960,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 {
 	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
-	struct strbuf envblk, args;
-	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
-	unsigned flags;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 
 	/* Determine whether or not we are associated to a console */
@@ -979,7 +979,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * instead of CREATE_NO_WINDOW to make ssh
 		 * recognize that it has no console.
 		 */
-		flags = DETACHED_PROCESS;
+		flags |= DETACHED_PROCESS;
 	} else {
 		/* There is already a console. If we specified
 		 * DETACHED_PROCESS here, too, Windows would
@@ -987,7 +987,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * The same is true for CREATE_NO_WINDOW.
 		 * Go figure!
 		 */
-		flags = 0;
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
@@ -1026,6 +1025,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
+		int size = 0, wenvsz = 0, wenvpos = 0;
 
 		for (e = env; *e; e++)
 			count++;
@@ -1035,20 +1035,22 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
 		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
 
-		strbuf_init(&envblk, 0);
+		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
-			strbuf_addstr(&envblk, *e);
-			strbuf_addch(&envblk, '\0');
+			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
 		}
+		/* add final \0 terminator */
+		wenvblk[wenvpos] = 0;
 		free(sorted_env);
 	}
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
+		wenvblk, dir ? wdir : NULL, &si, &pi);
 
-	if (env)
-		strbuf_release(&envblk);
+	free(wenvblk);
 	free(wargs);
 
 	if (!ret) {

From 540e4813127b840c630ef5f056279a9992505ea2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 25 Apr 2011 23:32:27 +0100
Subject: [PATCH 3109/3720] Win32: Unicode environment (incoming)

Convert environment from UTF-16 to UTF-8 on startup.

No changes to getenv() are necessary, as the MSVCRT version is implemented
on top of char **environ.

However, putenv / _wputenv from MSVCRT no longer work, for two reasons:
1. they try to keep environ, _wenviron and the Win32 process environment
in sync, using the default system encoding instead of UTF-8 to convert
between charsets
2. msysgit and MSVCRT use different allocators, memory allocated in git
cannot be freed by the CRT and vice versa

Implement mingw_putenv using the env_setenv helper function from the
environment merge code.

Note that in case of memory allocation failure, putenv now dies with error
message (due to xrealloc) instead of failing with ENOMEM. As git assumes
setenv / putenv to always succeed, this prevents it from continuing with
incorrect settings.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0422100eab..82a97e589e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1285,6 +1285,12 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -2067,6 +2073,11 @@ void mingw_startup()
 	maxlen = wcslen(_wpgmptr);
 	for (i = 1; i < argc; i++)
 		maxlen = max(maxlen, wcslen(wargv[i]));
+	for (i = 0; wenv[i]; i++)
+		maxlen = max(maxlen, wcslen(wenv[i]));
+
+	/* nedmalloc can't free CRT memory, allocate resizable environment list */
+	environ = xcalloc(i + 1, sizeof(char*));
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2079,6 +2090,10 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wargv[i], maxlen);
 		__argv[i] = xmemdupz(buffer, len);
 	}
+	for (i = 0; wenv[i]; i++) {
+		len = xwcstoutf(buffer, wenv[i], maxlen);
+		environ[i] = xmemdupz(buffer, len);
+	}
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
diff --git a/compat/mingw.h b/compat/mingw.h
index ea8c1f8993..af1574c435 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -200,6 +200,8 @@ char *mingw_getcwd(char *pointer, int len);
 
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
+int mingw_putenv(const char *namevalue);
+#define putenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From dc984940af9747d856ecb2c8e929d944875ac75a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 20 Aug 2011 14:27:02 +0200
Subject: [PATCH 3110/3720] MinGW: disable legacy encoding tests

On Windows, all native APIs are Unicode-based. It is impossible to pass
legacy encoded byte arrays to a process via command line or environment
variables. Disable the tests that try to do so.

In t3901, most tests still work if we don't mess up the repository encoding
in setup, so don't switch to ISO-8859-1 on MinGW.

Note that i18n tests that do their encoding tricks via encoded files (such
as t3900) are not affected by this.

Signed-off-by: Karsten Blees 
---
 t/t3901-i18n-patch.sh | 19 +++++++++++--------
 t/t4201-shortlog.sh   |  6 +++---
 t/t8005-blame-i18n.sh |  8 ++++----
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 31a5770b34..55c8a2f576 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -54,10 +54,13 @@ test_expect_success setup '
 	git add yours &&
 	git commit -s -m "Second on side" &&
 
-	# the second one on the side branch is ISO-8859-1
-	git config i18n.commitencoding ISO8859-1 &&
-	# use author and committer name in ISO-8859-1 to match it.
-	. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+	if test_have_prereq NOT_MINGW
+	then
+		# the second one on the side branch is ISO-8859-1
+		git config i18n.commitencoding ISO8859-1 &&
+		# use author and committer name in ISO-8859-1 to match it.
+		. "$TEST_DIRECTORY"/t3901-8859-1.txt
+	fi &&
 	test_tick &&
 	echo Yet another >theirs &&
 	git add theirs &&
@@ -119,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
 	check_encoding 2
 '
 
-test_expect_success 'rebase (L/L)' '
+test_expect_success NOT_MINGW 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
 	git config i18n.commitencoding ISO8859-1 &&
 	git config i18n.logoutputencoding ISO8859-1 &&
@@ -131,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 	check_encoding 2 8859
 '
 
-test_expect_success 'rebase (L/U)' '
+test_expect_success NOT_MINGW 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
 	git config i18n.commitencoding ISO8859-1 &&
@@ -159,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/L)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
 	git config i18n.commitencoding ISO8859-1 &&
@@ -189,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/U)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6872ba1a42..48963811bf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
 	test_cmp expect log.predictable
 '
 
-test_expect_success 'shortlog wrapping' '
+test_expect_success NOT_MINGW 'shortlog wrapping' '
 	cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
 	test_cmp expect out
 '
 
-test_expect_success 'shortlog from non-git directory' '
+test_expect_success NOT_MINGW 'shortlog from non-git directory' '
 	git log HEAD >log &&
 	GIT_DIR=non-existing git shortlog -w out &&
 	test_cmp expect out
@@ -135,7 +135,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success 'shortlog encoding' '
+test_expect_success NOT_MINGW 'shortlog encoding' '
 	git reset --hard "$commit" &&
 	git config --unset i18n.commitencoding &&
 	echo 2 > a1 &&
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index cb390559f9..a6e73d0635 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.commitencoding' '
 	git blame --incremental file | \
 		egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.logoutputencoding' '
 	git config i18n.logoutputencoding eucJP &&
 	git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=UTF-8' '
 	git blame --incremental --encoding=UTF-8 file | \
 		egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=none' '
 	git blame --incremental --encoding=none file | \
 		egrep "^(author|summary) " > actual &&

From 3194f181e99c631e52777739e48b5de9ab995079 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:29:40 +0100
Subject: [PATCH 3111/3720] Win32: fix environment memory leaks

All functions that modify the environment have memory leaks.

Disable gitunsetenv in the Makefile and use env_setenv (via mingw_putenv)
instead (this frees removed environment entries).

Move xstrdup from env_setenv to make_augmented_environ, so that
mingw_putenv no longer copies the environment entries (according to POSIX
[1], "the string [...] shall become part of the environment"). This also
fixes the memory leak in gitsetenv, which expects a POSIX compliant putenv.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html

Note: This patch depends on taking control of char **environ and having
our own mingw_putenv (both introduced in "Win32: Unicode environment
(incoming)").

Signed-off-by: Karsten Blees 
---
 Makefile       |  2 --
 compat/mingw.c | 10 ++++++----
 compat/mingw.h |  1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index c82f297f0f..77111b1f46 100644
--- a/Makefile
+++ b/Makefile
@@ -1160,7 +1160,6 @@ ifeq ($(uname_S),Windows)
 	NO_IPV6 = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
@@ -1257,7 +1256,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SYMLINK_HEAD = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index 82a97e589e..f7fe998e74 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1258,14 +1258,14 @@ static char **env_setenv(char **env, const char *name)
 			for (i = 0; env[i]; i++)
 				;
 			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 			env[i+1] = NULL;
 		}
 	}
 	else {
 		free(env[i]);
 		if (*eq)
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 		else
 			for (; env[i]; i++)
 				env[i] = env[i+1];
@@ -1280,8 +1280,10 @@ char **make_augmented_environ(const char *const *vars)
 {
 	char **env = copy_environ();
 
-	while (*vars)
-		env = env_setenv(env, *vars++);
+	while (*vars) {
+		const char *v = *vars++;
+		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+	}
 	return env;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index af1574c435..ba21474515 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -202,6 +202,7 @@ char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 int mingw_putenv(const char *namevalue);
 #define putenv mingw_putenv
+#define unsetenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 08353ef24c1597b447428b3265c746ebe6179a40 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 23:42:09 +0100
Subject: [PATCH 3112/3720] Win32: unify environment case-sensitivity

The environment on Windows is case-insensitive. Some environment functions
(such as unsetenv and make_augmented_environ) have always used case-
sensitive comparisons instead, while others (getenv, putenv, sorting in
spawn*) were case-insensitive.

Prevent potential inconsistencies by using case-insensitive comparison in
lookup_env (used by putenv, unsetenv and make_augmented_environ).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f7fe998e74..7d38415024 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1237,8 +1237,7 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 	int i;
 
 	for (i = 0; env[i]; i++) {
-		if (0 == strncmp(env[i], name, nmln)
-		    && '=' == env[i][nmln])
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
 			/* matches */
 			return i;
 	}

From 386413c4a2d5cde2f7d81cebd817de5eecd41364 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:33:17 +0100
Subject: [PATCH 3113/3720] Win32: simplify internal mingw_spawn* APIs

The only public spawn function that needs to tweak the environment is
mingw_spawnvpe (called from start_command). Nevertheless, all internal
spawn* functions take an env parameter and needlessly pass the global
char **environ around. Remove the env parameter where it's not needed.

This removes the internal mingw_execve abstraction, which is no longer
needed.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 7d38415024..2c7f2d7234 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1080,10 +1080,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-			   int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -1125,7 +1124,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 	return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
 	const char *interpr = parse_interpreter(cmd);
 	char **path;
@@ -1143,7 +1142,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 		argv2 = xmalloc(sizeof(*argv) * (argc+1));
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-		pid = mingw_spawnve(prog, argv2, env, 1);
+		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -1158,13 +1157,13 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 	return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+void mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
-	if (!try_shell_exec(cmd, argv, (char **)env)) {
+	if (!try_shell_exec(cmd, argv)) {
 		int pid, status;
 
-		pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
 			return;
 		if (waitpid(pid, &status, 0) < 0)
@@ -1179,7 +1178,7 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	char *prog = path_lookup(cmd, path, 0);
 
 	if (prog) {
-		mingw_execve(prog, argv, environ);
+		mingw_execv(prog, argv);
 		free(prog);
 	} else
 		errno = ENOENT;
@@ -1187,11 +1186,6 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	free_path_split(path);
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
-{
-	mingw_execve(cmd, argv, environ);
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
 	if (pid > 0 && sig == SIGTERM) {

From 6a18b48e883024fdeba43005f370000695c52e6f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:05:04 +0100
Subject: [PATCH 3114/3720] Win32: move environment functions

Move environment helper functions up so that they can be reused by
mingw_getenv and mingw_spawnve_fd in subsequent patches.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 106 ++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2c7f2d7234..1bea9716e2 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -740,6 +740,53 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
+static int env_compare(const void *a, const void *b)
+{
+	char *const *ea = a;
+	char *const *eb = b;
+	return strcasecmp(*ea, *eb);
+}
+
+static int lookup_env(char **env, const char *name, size_t nmln)
+{
+	int i;
+
+	for (i = 0; env[i]; i++) {
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
+			/* matches */
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * If name contains '=', then sets the variable, otherwise it unsets it
+ */
+static char **env_setenv(char **env, const char *name)
+{
+	char *eq = strchrnul(name, '=');
+	int i = lookup_env(env, name, eq-name);
+
+	if (i < 0) {
+		if (*eq) {
+			for (i = 0; env[i]; i++)
+				;
+			env = xrealloc(env, (i+2)*sizeof(*env));
+			env[i] = (char*) name;
+			env[i+1] = NULL;
+		}
+	}
+	else {
+		free(env[i]);
+		if (*eq)
+			env[i] = (char*) name;
+		else
+			for (; env[i]; i++)
+				env[i] = env[i+1];
+	}
+	return env;
+}
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -757,6 +804,12 @@ char *mingw_getenv(const char *name)
 	return result;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -939,13 +992,6 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
-static int env_compare(const void *a, const void *b)
-{
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
-}
-
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1226,46 +1272,6 @@ void free_environ(char **env)
 	free(env);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
-{
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
-	}
-	return -1;
-}
-
-/*
- * If name contains '=', then sets the variable, otherwise it unsets it
- */
-static char **env_setenv(char **env, const char *name)
-{
-	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
-
-	if (i < 0) {
-		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
-		}
-	}
-	else {
-		free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-	}
-	return env;
-}
-
 /*
  * Copies global environ and adjusts variables as specified by vars.
  */
@@ -1280,12 +1286,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-int mingw_putenv(const char *namevalue)
-{
-	environ = env_setenv(environ, namevalue);
-	return 0;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From f4e8b8c2a1e9a89be79eac51b3f66487daccff53 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Wed, 5 Oct 2011 22:01:46 +0200
Subject: [PATCH 3115/3720] Win32: unify environment function names

Environment helper functions use random naming ('env' prefix or suffix or
both, with or without '_'). Change to POSIX naming scheme ('env' suffix,
no '_').

Env_setenv has more in common with putenv than setenv. Change to do_putenv.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1bea9716e2..cbab870760 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -740,14 +740,14 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int env_compare(const void *a, const void *b)
+static int compareenv(const void *a, const void *b)
 {
 	char *const *ea = a;
 	char *const *eb = b;
 	return strcasecmp(*ea, *eb);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
+static int lookupenv(char **env, const char *name, size_t nmln)
 {
 	int i;
 
@@ -762,10 +762,10 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **env_setenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name)
 {
 	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
+	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
@@ -806,7 +806,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = env_setenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue);
 	return 0;
 }
 
@@ -1079,7 +1079,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		/* environment must be sorted */
 		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
 
 		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
@@ -1281,7 +1281,7 @@ char **make_augmented_environ(const char *const *vars)
 
 	while (*vars) {
 		const char *v = *vars++;
-		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
 	}
 	return env;
 }

From 459a4a676440fe527931d2ec83e4bed93fc14c75 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:31:57 +0100
Subject: [PATCH 3116/3720] Win32: factor out environment block creation

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 55 +++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index cbab870760..efdb5a3a6a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -992,6 +992,36 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
+/*
+ * Create environment block suitable for CreateProcess.
+ */
+static wchar_t *make_environment_block(char **env)
+{
+	wchar_t *wenvblk = NULL;
+	int count = 0;
+	char **e, **tmpenv;
+	int size = 0, wenvsz = 0, wenvpos = 0;
+
+	for (e = env; *e; e++)
+		count++;
+
+	/* environment must be sorted */
+	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+
+	/* create environment block from temporary environment */
+	for (e = tmpenv; *e; e++) {
+		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+	}
+	/* add final \0 terminator */
+	wenvblk[wenvpos] = 0;
+	free(tmpenv);
+	return wenvblk;
+}
+
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1068,29 +1098,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env) {
-		int count = 0;
-		char **e, **sorted_env;
-		int size = 0, wenvsz = 0, wenvpos = 0;
-
-		for (e = env; *e; e++)
-			count++;
-
-		/* environment must be sorted */
-		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
-		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
-
-		/* create environment block from temporary environment */
-		for (e = sorted_env; *e; e++) {
-			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
-			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
-		}
-		/* add final \0 terminator */
-		wenvblk[wenvpos] = 0;
-		free(sorted_env);
-	}
+	if (env)
+		wenvblk = make_environment_block(env);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,

From ea2b04d73d366fc4a4751b7972bab5b32048e1de Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:57:14 +0100
Subject: [PATCH 3117/3720] Win32: don't copy the environment twice when
 spawning child processes

When spawning child processes via start_command(), the environment and all
environment entries are copied twice. First by make_augmented_environ /
copy_environ to merge with child_process.env. Then a second time by
make_environment_block to create a sorted environment block string as
required by CreateProcess.

Move the merge logic to make_environment_block so that we only need to copy
the environment once. This changes semantics of the env parameter: it now
expects a delta (such as child_process.env) rather than a full environment.
This is not a problem as the parameter is only used by start_command()
(all other callers previously passed char **environ, and now pass NULL).

The merge logic no longer xstrdup()s the environment strings, so do_putenv
must not free them. Add a parameter to distinguish this from normal putenv.

Remove the now unused make_augmented_environ / free_environ API.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 74 ++++++++++++++++----------------------------------
 compat/mingw.h |  6 ----
 run-command.c  | 10 ++-----
 3 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index efdb5a3a6a..040cd8baf5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -762,7 +762,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **do_putenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
@@ -777,7 +777,8 @@ static char **do_putenv(char **env, const char *name)
 		}
 	}
 	else {
-		free(env[i]);
+		if (free_old)
+			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
 		else
@@ -806,7 +807,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue, 1);
 	return 0;
 }
 
@@ -993,21 +994,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 }
 
 /*
- * Create environment block suitable for CreateProcess.
+ * Create environment block suitable for CreateProcess. Merges current
+ * process environment and the supplied environment changes.
  */
-static wchar_t *make_environment_block(char **env)
+static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
 	int count = 0;
 	char **e, **tmpenv;
 	int size = 0, wenvsz = 0, wenvpos = 0;
 
-	for (e = env; *e; e++)
+	while (environ[count])
 		count++;
 
-	/* environment must be sorted */
+	/* copy the environment */
 	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+
+	/* merge supplied environment changes into the temporary environment */
+	for (e = deltaenv; e && *e; e++)
+		tmpenv = do_putenv(tmpenv, *e, 0);
+
+	/* environment must be sorted */
+	for (count = 0; tmpenv[count]; )
+		count++;
 	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
 
 	/* create environment block from temporary environment */
@@ -1030,7 +1040,7 @@ struct pinfo_t {
 struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
-static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
@@ -1098,8 +1108,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env)
-		wenvblk = make_environment_block(env);
+	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1137,10 +1146,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
 static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 		     const char *dir,
 		     int fhin, int fhout, int fherr)
 {
@@ -1164,14 +1173,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 				pid = -1;
 			}
 			else {
-				pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
 						       fhin, fhout, fherr);
 				free(iprog);
 			}
 			argv[0] = argv0;
 		}
 		else
-			pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
 					       fhin, fhout, fherr);
 		free(prog);
 	}
@@ -1260,41 +1269,6 @@ int mingw_kill(pid_t pid, int sig)
 	return -1;
 }
 
-static char **copy_environ(void)
-{
-	char **env;
-	int i = 0;
-	while (environ[i])
-		i++;
-	env = xmalloc((i+1)*sizeof(*env));
-	for (i = 0; environ[i]; i++)
-		env[i] = xstrdup(environ[i]);
-	env[i] = NULL;
-	return env;
-}
-
-void free_environ(char **env)
-{
-	int i;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-/*
- * Copies global environ and adjusts variables as specified by vars.
- */
-char **make_augmented_environ(const char *const *vars)
-{
-	char **env = copy_environ();
-
-	while (*vars) {
-		const char *v = *vars++;
-		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
-	}
-	return env;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
diff --git a/compat/mingw.h b/compat/mingw.h
index ba21474515..04b6523255 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -335,12 +335,6 @@ void mingw_open_html(const char *path);
 void mingw_mark_as_git_dir(const char *dir);
 #define mark_as_git_dir mingw_mark_as_git_dir
 
-/*
- * helpers
- */
-
-char **make_augmented_environ(const char *const *vars);
-void free_environ(char **env);
 
 /**
  * Converts UTF-8 encoded string to UTF-16LE.
diff --git a/run-command.c b/run-command.c
index 1db8abf984..6d0dc3da91 100644
--- a/run-command.c
+++ b/run-command.c
@@ -381,7 +381,6 @@ fail_pipe:
 {
 	int fhin = 0, fhout = 1, fherr = 2;
 	const char **sargv = cmd->argv;
-	char **env = environ;
 
 	if (cmd->no_stdin)
 		fhin = open("/dev/null", O_RDWR);
@@ -406,25 +405,20 @@ fail_pipe:
 	else if (cmd->out > 1)
 		fhout = dup(cmd->out);
 
-	if (cmd->env)
-		env = make_augmented_environ(cmd->env);
-
 	if (cmd->git_cmd) {
 		cmd->argv = prepare_git_cmd(cmd->argv);
 	} else if (cmd->use_shell) {
 		cmd->argv = prepare_shell_cmd(cmd->argv);
 	}
 
-	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
-				  fhin, fhout, fherr);
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
 	failed_errno = errno;
 	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 		error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 	if (cmd->clean_on_exit && cmd->pid >= 0)
 		mark_child_for_cleanup(cmd->pid);
 
-	if (cmd->env)
-		free_environ(env);
 	if (cmd->git_cmd)
 		free(cmd->argv);
 

From da6c3a796ad3cdd0e95d6df01fe25aae3908bd4b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:00:35 +0100
Subject: [PATCH 3118/3720] Win32: reduce environment array reallocations

Move environment array reallocation from do_putenv to the respective
callers. Keep track of the environment size in a global variable. Use
ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a
sufficiently sized environment array in make_environment_block to prevent
reallocations.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 60 ++++++++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 040cd8baf5..e1f59f090f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -761,19 +761,19 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
+ * Size includes the terminating NULL. Env must have room for size + 1 entries
+ * (in case of insert). Returns the new size. Optionally frees removed entries.
  */
-static char **do_putenv(char **env, const char *name, int free_old)
+static int do_putenv(char **env, const char *name, int size, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
+			env[size - 1] = (char*) name;
+			env[size] = NULL;
+			size++;
 		}
 	}
 	else {
@@ -781,13 +781,20 @@ static char **do_putenv(char **env, const char *name, int free_old)
 			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
-		else
+		else {
 			for (; env[i]; i++)
 				env[i] = env[i+1];
+			size--;
+		}
 	}
-	return env;
+	return size;
 }
 
+/* used number of elements of environ array, including terminating NULL */
+static int environ_size = 0;
+/* allocated size of environ array, in bytes */
+static int environ_alloc = 0;
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -807,7 +814,8 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue, 1);
+	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
+	environ_size = do_putenv(environ, namevalue, environ_size, 1);
 	return 0;
 }
 
@@ -1000,31 +1008,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
-	int count = 0;
-	char **e, **tmpenv;
-	int size = 0, wenvsz = 0, wenvpos = 0;
+	char **tmpenv;
+	int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
 
-	while (environ[count])
-		count++;
+	while (deltaenv && deltaenv[i])
+		i++;
 
-	/* copy the environment */
-	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+	/* copy the environment, leaving space for changes */
+	tmpenv = xmalloc((size + i) * sizeof(char*));
+	memcpy(tmpenv, environ, size * sizeof(char*));
 
 	/* merge supplied environment changes into the temporary environment */
-	for (e = deltaenv; e && *e; e++)
-		tmpenv = do_putenv(tmpenv, *e, 0);
+	for (i = 0; deltaenv && deltaenv[i]; i++)
+		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
 	/* environment must be sorted */
-	for (count = 0; tmpenv[count]; )
-		count++;
-	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
 
 	/* create environment block from temporary environment */
-	for (e = tmpenv; *e; e++) {
-		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+	for (i = 0; tmpenv[i]; i++) {
+		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
 		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+		wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
 	}
 	/* add final \0 terminator */
 	wenvblk[wenvpos] = 0;
@@ -2055,7 +2060,9 @@ void mingw_startup()
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
 	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = xcalloc(i + 1, sizeof(char*));
+	environ = NULL;
+	environ_size = i + 1;
+	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2072,6 +2079,7 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wenv[i], maxlen);
 		environ[i] = xmemdupz(buffer, len);
 	}
+	environ[i] = NULL;
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */

From 944e19a9048624d820ca1d03b7fe1a926b4ed747 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:30:02 +0100
Subject: [PATCH 3119/3720] Win32: keep the environment sorted

The Windows environment is sorted, keep it that way for O(log n)
environment access.

Change compareenv to compare only the keys, so that it can be used to
find an entry irrespective of the value.

Change lookupenv to binary seach for an entry. Return one's complement of
the insert position if not found (libc's bsearch returns NULL).

Replace MSVCRT's getenv with a minimal do_getenv based on the binary search
function.

Change do_putenv to insert new entries at the correct position. Simplify
the function by swapping if conditions and using memmove instead of for
loops.

Move qsort from make_environment_block to mingw_startup. We still need to
sort on startup to make sure that the environment is sorted according to
our compareenv function (while Win32 / CreateProcess requires the
environment block to be sorted case-insensitively, CreateProcess currently
doesn't enforce this, and some applications such as bash just don't care).

Note that environment functions are _not_ thread-safe and are not required
to be so by POSIX, the application is responsible for synchronizing access
to the environment. MSVCRT's getenv and our new getenv implementation are
better than that in that they are thread-safe with respect to other getenv
calls as long as the environment is not modified. Git's indiscriminate use
of getenv in background threads currently requires this property.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 98 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 62 insertions(+), 36 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e1f59f090f..5041ba98ae 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -740,23 +740,42 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int compareenv(const void *a, const void *b)
+/*
+ * Compare environment entries by key (i.e. stopping at '=' or '\0').
+ */
+static int compareenv(const void *v1, const void *v2)
 {
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
+	const char *e1 = *(const char**)v1;
+	const char *e2 = *(const char**)v2;
+
+	for (;;) {
+		int c1 = *e1++;
+		int c2 = *e2++;
+		c1 = (c1 == '=') ? 0 : tolower(c1);
+		c2 = (c2 == '=') ? 0 : tolower(c2);
+		if (c1 > c2)
+			return 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 == 0)
+			return 0;
+	}
 }
 
-static int lookupenv(char **env, const char *name, size_t nmln)
+static int bsearchenv(char **env, const char *name, size_t size)
 {
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
+	unsigned low = 0, high = size;
+	while (low < high) {
+		unsigned mid = low + ((high - low) >> 1);
+		int cmp = compareenv(&env[mid], &name);
+		if (cmp < 0)
+			low = mid + 1;
+		else if (cmp > 0)
+			high = mid;
+		else
+			return mid;
 	}
-	return -1;
+	return ~low; /* not found, return 1's complement of insert position */
 }
 
 /*
@@ -766,26 +785,24 @@ static int lookupenv(char **env, const char *name, size_t nmln)
  */
 static int do_putenv(char **env, const char *name, int size, int free_old)
 {
-	char *eq = strchrnul(name, '=');
-	int i = lookupenv(env, name, eq-name);
+	int i = bsearchenv(env, name, size - 1);
 
-	if (i < 0) {
-		if (*eq) {
-			env[size - 1] = (char*) name;
-			env[size] = NULL;
+	/* optionally free removed / replaced entry */
+	if (i >= 0 && free_old)
+		free(env[i]);
+
+	if (strchr(name, '=')) {
+		/* if new value ('key=value') is specified, insert or replace entry */
+		if (i < 0) {
+			i = ~i;
+			memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
 			size++;
 		}
-	}
-	else {
-		if (free_old)
-			free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else {
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-			size--;
-		}
+		env[i] = (char*) name;
+	} else if (i >= 0) {
+		/* otherwise ('key') remove existing entry */
+		size--;
+		memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
 	}
 	return size;
 }
@@ -795,15 +812,24 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-#undef getenv
+static char *do_getenv(const char *name)
+{
+	char *value;
+	int pos = bsearchenv(environ, name, environ_size - 1);
+	if (pos < 0)
+		return NULL;
+	value = strchr(environ[pos], '=');
+	return value ? &value[1] : NULL;
+}
+
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv(name);
+	char *result = do_getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
+		result = do_getenv("TMP");
 		if (!result)
-			result = getenv("TEMP");
+			result = do_getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */
@@ -1022,9 +1048,6 @@ static wchar_t *make_environment_block(char **deltaenv)
 	for (i = 0; deltaenv && deltaenv[i]; i++)
 		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
-	/* environment must be sorted */
-	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
-
 	/* create environment block from temporary environment */
 	for (i = 0; tmpenv[i]; i++) {
 		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
@@ -2082,6 +2105,9 @@ void mingw_startup()
 	environ[i] = NULL;
 	free(buffer);
 
+	/* sort environment for O(log n) getenv / putenv */
+	qsort(environ, i, sizeof(char*), compareenv);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 39b8ab5d07b5d8fe175090d0f3c908ca5e01f350 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:35:26 +0100
Subject: [PATCH 3120/3720] Win32: patch Windows environment on startup

Fix Windows specific environment settings on startup rather than checking
for special values on every getenv call.

As a side effect, this makes the patched environment (i.e. with properly
initialized TMPDIR and TERM) available to child processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 5041ba98ae..d10734b0eb 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -812,7 +812,7 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-static char *do_getenv(const char *name)
+char *mingw_getenv(const char *name)
 {
 	char *value;
 	int pos = bsearchenv(environ, name, environ_size - 1);
@@ -822,22 +822,6 @@ static char *do_getenv(const char *name)
 	return value ? &value[1] : NULL;
 }
 
-char *mingw_getenv(const char *name)
-{
-	char *result = do_getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = do_getenv("TMP");
-		if (!result)
-			result = do_getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 int mingw_putenv(const char *namevalue)
 {
 	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
@@ -2108,6 +2092,21 @@ void mingw_startup()
 	/* sort environment for O(log n) getenv / putenv */
 	qsort(environ, i, sizeof(char*), compareenv);
 
+	/* fix Windows specific environment settings */
+
+	/* on Windows it is TMP and TEMP */
+	if (!getenv("TMPDIR")) {
+		const char *tmp = getenv("TMP");
+		if (!tmp)
+			tmp = getenv("TEMP");
+		if (tmp)
+			setenv("TMPDIR", tmp, 1);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "winansi", 1);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 53dc8460b9d46be558dc19b491a79027f0b7ac7e Mon Sep 17 00:00:00 2001
From: Junio C Hamano 
Date: Tue, 13 Mar 2012 09:51:57 -0700
Subject: [PATCH 3121/3720] Revert earlier parts of jc/fmt-merge-msg-people
 topic

---
 builtin/fmt-merge-msg.c         | 104 ++------------------------------
 t/t6200-fmt-merge-msg.sh        |  32 +---------
 t/t7600-merge.sh                |   1 -
 t/t7604-merge-custom-message.sh |   1 -
 4 files changed, 7 insertions(+), 131 deletions(-)

diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 8ddefb39db..c81a7fef26 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -27,8 +27,6 @@ int fmt_merge_msg_config(const char *key, const char *value, void *cb)
 			merge_log_config = DEFAULT_MERGE_LOG_LEN;
 	} else if (!strcmp(key, "merge.branchdesc")) {
 		use_branch_desc = git_config_bool(key, value);
-	} else {
-		return git_default_config(key, value, cb);
 	}
 	return 0;
 }
@@ -182,91 +180,6 @@ static void add_branch_desc(struct strbuf *out, const char *name)
 	strbuf_release(&desc);
 }
 
-#define util_as_int(elem) ((int)((elem)->util))
-
-static void record_person(int which, struct string_list *people,
-			  struct commit *commit)
-{
-	char name_buf[MAX_GITNAME], *name, *name_end;
-	struct string_list_item *elem;
-	const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
-
-	name = strstr(commit->buffer, field);
-	if (!name)
-		return;
-	name += strlen(field);
-	name_end = strchrnul(name, '<');
-	if (*name_end)
-		name_end--;
-	while (isspace(*name_end) && name <= name_end)
-		name_end--;
-	if (name_end < name || name + MAX_GITNAME <= name_end)
-		return;
-	memcpy(name_buf, name, name_end - name + 1);
-	name_buf[name_end - name + 1] = '\0';
-
-	elem = string_list_lookup(people, name_buf);
-	if (!elem) {
-		elem = string_list_insert(people, name_buf);
-		elem->util = (void *)0;
-	}
-	elem->util = (void*)((intptr_t)(util_as_int(elem) + 1));
-}
-
-static int cmp_string_list_util_as_int(const void *a_, const void *b_)
-{
-	const struct string_list_item *a = a_, *b = b_;
-	return util_as_int(b) - util_as_int(a);
-}
-
-static void add_people_count(struct strbuf *out, struct string_list *people)
-{
-	if (people->nr == 1)
-		strbuf_addf(out, "%s", people->items[0].string);
-	else if (people->nr == 2)
-		strbuf_addf(out, "%s (%d) and %s (%d)",
-			    people->items[0].string,
-			    util_as_int(&people->items[0]),
-			    people->items[1].string,
-			    util_as_int(&people->items[1]));
-	else if (people->nr)
-		strbuf_addf(out, "%s (%d) and others",
-			    people->items[0].string,
-			    util_as_int(&people->items[0]));
-}
-
-static int committer_is_me(const char *name)
-{
-	const char *me = git_committer_info(IDENT_NO_DATE);
-	return (me &&
-		(me = skip_prefix(me, name)) != NULL &&
-		skip_prefix(me, " <"));
-}
-
-static void add_people_info(struct strbuf *out,
-			    struct string_list *authors,
-			    struct string_list *committers)
-{
-	if (authors->nr)
-		qsort(authors->items,
-		      authors->nr, sizeof(authors->items[0]),
-		      cmp_string_list_util_as_int);
-	if (committers->nr)
-		qsort(committers->items,
-		      committers->nr, sizeof(committers->items[0]),
-		      cmp_string_list_util_as_int);
-
-	if (authors->nr) {
-		strbuf_addstr(out, "\nBy ");
-		add_people_count(out, authors);
-	}
-	if (committers->nr == 1 &&
-	    committer_is_me(committers->items->string))
-		return;
-	strbuf_addstr(out, "\nvia ");
-	add_people_count(out, committers);
-}
-
 static void shortlog(const char *name,
 		     struct origin_data *origin_data,
 		     struct commit *head,
@@ -277,8 +190,6 @@ static void shortlog(const char *name,
 	struct commit *commit;
 	struct object *branch;
 	struct string_list subjects = STRING_LIST_INIT_DUP;
-	struct string_list authors = STRING_LIST_INIT_DUP;
-	struct string_list committers = STRING_LIST_INIT_DUP;
 	int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
 	struct strbuf sb = STRBUF_INIT;
 	const unsigned char *sha1 = origin_data->sha1;
@@ -288,6 +199,7 @@ static void shortlog(const char *name,
 		return;
 
 	setup_revisions(0, NULL, rev, NULL);
+	rev->ignore_merges = 1;
 	add_pending_object(rev, branch, name);
 	add_pending_object(rev, &head->object, "^HEAD");
 	head->object.flags |= UNINTERESTING;
@@ -296,15 +208,10 @@ static void shortlog(const char *name,
 	while ((commit = get_revision(rev)) != NULL) {
 		struct pretty_print_context ctx = {0};
 
-		if (commit->parents && commit->parents->next) {
-			/* do not list a merge but count committer */
-			record_person('c', &committers, commit);
+		/* ignore merges */
+		if (commit->parents && commit->parents->next)
 			continue;
-		}
-		if (!count)
-			/* the 'tip' committer */
-			record_person('c', &committers, commit);
-		record_person('a', &authors, commit);
+
 		count++;
 		if (subjects.nr > limit)
 			continue;
@@ -319,7 +226,6 @@ static void shortlog(const char *name,
 			string_list_append(&subjects, strbuf_detach(&sb, NULL));
 	}
 
-	add_people_info(out, &authors, &committers);
 	if (count > limit)
 		strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
 	else
@@ -340,8 +246,6 @@ static void shortlog(const char *name,
 	rev->commits = NULL;
 	rev->pending.nr = 0;
 
-	string_list_clear(&authors, 0);
-	string_list_clear(&committers, 0);
 	string_list_clear(&subjects, 0);
 }
 
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index b90015df1c..9a16806921 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -35,18 +35,15 @@ test_expect_success setup '
 
 	echo "l3" >two &&
 	test_tick &&
-	GIT_COMMITTER_NAME="Another Committer" \
-	GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #3" &&
+	git commit -a -m "Left #3" &&
 
 	echo "l4" >two &&
 	test_tick &&
-	GIT_COMMITTER_NAME="Another Committer" \
-	GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #4" &&
+	git commit -a -m "Left #4" &&
 
 	echo "l5" >two &&
 	test_tick &&
-	GIT_COMMITTER_NAME="Another Committer" \
-	GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #5" &&
+	git commit -a -m "Left #5" &&
 	git tag tag-l5 &&
 
 	git checkout right &&
@@ -102,8 +99,6 @@ test_expect_success '[merge] summary/log configuration' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -149,8 +144,6 @@ test_expect_success 'merge.log=3 limits shortlog length' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* left: (5 commits)
 	  Left #5
 	  Left #4
@@ -166,8 +159,6 @@ test_expect_success 'merge.log=5 shows all 5 commits' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -190,8 +181,6 @@ test_expect_success '--log=3 limits shortlog length' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* left: (5 commits)
 	  Left #5
 	  Left #4
@@ -207,8 +196,6 @@ test_expect_success '--log=5 shows all 5 commits' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -238,8 +225,6 @@ test_expect_success 'fmt-merge-msg -m' '
 	cat >expected.log <<-EOF &&
 	Sync with left
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* ${apos}left${apos} of $(pwd):
 	  Left #5
 	  Left #4
@@ -271,8 +256,6 @@ test_expect_success 'setup: expected shortlog for two branches' '
 	cat >expected <<-EOF
 	Merge branches ${apos}left${apos} and ${apos}right${apos}
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -280,7 +263,6 @@ test_expect_success 'setup: expected shortlog for two branches' '
 	  Common #2
 	  Common #1
 
-	By A U Thor
 	* right:
 	  Right #5
 	  Right #4
@@ -371,7 +353,6 @@ test_expect_success 'merge-msg tag' '
 	cat >expected <<-EOF &&
 	Merge tag ${apos}tag-r3${apos}
 
-	By A U Thor
 	* tag ${apos}tag-r3${apos}:
 	  Right #3
 	  Common #2
@@ -393,14 +374,11 @@ test_expect_success 'merge-msg two tags' '
 	cat >expected <<-EOF &&
 	Merge tags ${apos}tag-r3${apos} and ${apos}tag-l5${apos}
 
-	By A U Thor
 	* tag ${apos}tag-r3${apos}:
 	  Right #3
 	  Common #2
 	  Common #1
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* tag ${apos}tag-l5${apos}:
 	  Left #5
 	  Left #4
@@ -424,14 +402,11 @@ test_expect_success 'merge-msg tag and branch' '
 	cat >expected <<-EOF &&
 	Merge branch ${apos}left${apos}, tag ${apos}tag-r3${apos}
 
-	By A U Thor
 	* tag ${apos}tag-r3${apos}:
 	  Right #3
 	  Common #2
 	  Common #1
 
-	By Another Author (3) and A U Thor (2)
-	via Another Committer
 	* left:
 	  Left #5
 	  Left #4
@@ -456,7 +431,6 @@ test_expect_success 'merge-msg lots of commits' '
 		cat <<-EOF &&
 		Merge branch ${apos}long${apos}
 
-		By A U Thor
 		* long: (35 commits)
 		EOF
 
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index e09b932650..9e27bbf902 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -58,7 +58,6 @@ create_merge_msgs () {
 	} >squash.1-5-9 &&
 	echo >msg.nolog &&
 	{
-		echo "By A U Thor" &&
 		echo "* tag 'c3':" &&
 		echo "  commit 3" &&
 		echo
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index b84cea3498..89619cf446 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -11,7 +11,6 @@ create_merge_msgs() {
 
 	cp exp.subject exp.log &&
 	echo >>exp.log "" &&
-	echo >>exp.log "By A U Thor" &&
 	echo >>exp.log "* tag 'c2':" &&
 	echo >>exp.log "  c2"
 }

From b1063e648bca7cc9f5a330c8bf408f05c564f555 Mon Sep 17 00:00:00 2001
From: Matthieu Moy 
Date: Sat, 14 Jan 2012 19:55:36 +0100
Subject: [PATCH 3122/3720] bash-completion: don't add quoted space for ZSH
 (fix regression)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit a31e626 (completion: optimize refs completion) introduced a
regression for ZSH users: ref names were completed with a quoted trailing
space (i.e. "git checkout ma" completes to "git checkout master\ "). The
space is convenient for bash users since we use "-o nospace", but a
quoted space is worse than nothing. The absence of trailing space for ZSH
is a long-standing issue, that this patch is not fixing. We just fix the
regression by not appending a space when the shell is ZSH.

Original-patch-by: SZEDER Gábor 
Reported-by: Stefan Haller 
Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 contrib/completion/git-completion.bash | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index fba076dde2..f1f67b5fc4 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -508,6 +508,13 @@ __gitcomp ()
 __gitcomp_nl ()
 {
 	local IFS=$'\n'
+
+	# ZSH would quote the trailing space added with -S. bash users
+	# will appreciate the extra space to compensate the use of -o nospace.
+	if [ -n "${ZSH_VERSION-}" ] && [ "$suffix" = " " ]; then
+		suffix=""
+	fi
+
 	COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
 }
 

From ac941f9fe45a2b60c665d283f9e5e1c5421938d6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 3123/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index be1957a5e9..073c3f67e6 100644
--- a/Makefile
+++ b/Makefile
@@ -1194,16 +1194,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 83035cde1d98ac8dfd71143d3b1d2666c7a08733 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 3124/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index c081657be7..58d4da28c8 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -169,6 +169,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index a8aceb5aee..099eb72a20 100644
--- a/cache.h
+++ b/cache.h
@@ -605,6 +605,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..cc1b34999d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..699a3dd395 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -113,10 +113,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -318,6 +315,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index 68d32940f3..1759695d16 100644
--- a/config.c
+++ b/config.c
@@ -752,6 +752,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index c93b8f44df..bf6f0c29ed 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index ed11ad8119..14fa4e117a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -595,4 +595,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 6d94e06c4802938c7b62d4d49d9e928a64e8d8a7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 3125/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index cc1b34999d..665f6abc40 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 92eec32067a6ddfdd48da436d86458f87b4ec7d4 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 3126/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 12b36699951cbf68064d83ddecf17efa2c4ce348 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 3127/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From d27136e576e26ae2531e52c0bc7ea1ea81cde4cb Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 3128/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From a19c2fd8fc2c35df6b5b6e075f4824da9917dcc0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 3129/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 64ef3c4013..e2cda370fa 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9499,7 +9499,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From ddd49d4c01242bfa93d8c171518affc50a593db5 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 3130/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From bac046ce16987978ab9a7c79410d0b177a0c8c34 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 3131/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From ea87f775161c211795149c44e34e2b2af9dfe0b5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 3132/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 58d4da28c8..24a301f2d7 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1723,6 +1723,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 0afb8b2896..1b2bf5fe66 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -89,7 +91,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -410,6 +417,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -441,6 +486,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -469,6 +521,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b5417cc951..2482796454 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -995,4 +995,40 @@ test_expect_success 'push --prune refspec' '
 	! check_push_result $the_first_commit tmp/foo tmp/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 781cb78a94c2811cd66901ff440198d46e396a6d Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 3133/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index ef30c557c7..c42fb2a7aa 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 07f88a00e3a489854ab3b94a1bb761acd52d72c8 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 3134/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index c42fb2a7aa..03292fd832 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 24e40baef4bfaebc40a0aa472e03e1e5d4b08af2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 3135/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index d41a9bfb14..a3991b9673 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -169,7 +169,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = given_config_file;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 665f6abc40..e5f1c36995 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 699a3dd395..ec5c25c36d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -349,3 +349,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index 1759695d16..53fd956a88 100644
--- a/config.c
+++ b/config.c
@@ -960,7 +960,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 14fa4e117a..5911e8f7eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -599,4 +599,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index 6f2aa699ad..4cb0585cde 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 63398066bb7f5e4af7a9b7f8ed32e271883fbedc Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 12 Jun 2010 00:44:01 +0200
Subject: [PATCH 3136/3720] t7602: cope with CR/LF

The output of git-merge-octopus has CR/LF line endings, so let's just
strip the CR out.

Signed-off-by: Johannes Schindelin 
---
 t/t7602-merge-octopus-many.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 5783ebf3ab..1489bcff97 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -65,7 +65,8 @@ EOF
 
 test_expect_success 'merge output uses pretty names' '
 	git reset --hard c1 &&
-	git merge c2 c3 c4 >actual &&
+	git merge c2 c3 c4 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -79,7 +80,8 @@ Merge made by the 'octopus' strategy.
 EOF
 
 test_expect_success 'merge up-to-date output uses pretty names' '
-	git merge c4 c5 >actual &&
+	git merge c4 c5 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 
@@ -96,7 +98,8 @@ EOF
 
 test_expect_success 'merge fast-forward output uses pretty names' '
 	git reset --hard c0 &&
-	git merge c1 c2 >actual &&
+	git merge c1 c2 >actual.raw &&
+	tr -d "\r" < actual.raw > actual &&
 	test_cmp actual expected
 '
 

From d2ec5252f7f7c2527ed0a9455f4ee1f6f42585a5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 3137/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 4da0ddafc4..ef7191e562 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -564,7 +564,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -736,7 +737,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -812,7 +814,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -836,7 +838,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From 7ab122e3059c7f91b1c04a0bec0eedf650a07a60 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 3138/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 30ed4d74bb..0c3518205f 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 16a07c8d6d92d09cbad168cd3ab21b6bdcf299c1 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 3139/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 099eb72a20..56113436fc 100644
--- a/cache.h
+++ b/cache.h
@@ -758,7 +758,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index e5f1c36995..39ce7b446d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index ec5c25c36d..9111ce66e7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -309,6 +309,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 5911e8f7eb..39866a76c2 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 4cb0585cde..242074b1cf 100644
--- a/path.c
+++ b/path.c
@@ -660,10 +660,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 455d209b9d5826b070a5b3fa299f5ebeb60b1422 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 3140/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index a3991b9673..490e2ea4fd 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;

From 922e85b9aba55a42407a65e696d7ae62e55cb82e Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 3141/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 39ce7b446d..71adbc497a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 08144f6e5f7bfe231b5781cf91a8d73b9e58f02b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 3142/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 3be9c9c31fe365a242241a5886396c03b939d9dc Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 3143/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index e2cda370fa..928a25d904 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -365,7 +365,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9499,18 +9499,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9521,6 +9510,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 0ebe5e3127145c21a676e215185938e70404669f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 3144/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 71adbc497a..fe3cae3a38 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From d0a41e277525a9b5797c03f77e6587611c5872cf Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 3145/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9111ce66e7..60e281a7fe 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From c57751da5ee888b8ce17a221ddf8a83c9dbd3881 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 3146/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From f978beeadbdc593131d72af60d1699b6144f48e2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 3147/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 224fe839427a8525e24a5567ce667daf0d96dded Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 3148/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index cea8756866..9be97ab9ae 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From ac9bf9dd6924696f1bde5fe14b6b1226d9a654e9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 3149/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a8b5fad266..ec97589687 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4434,6 +4434,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 75612f8e5d398805b3534f59d8d398f5c5eb1e00 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 3150/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index ec97589687..3c2284f611 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4449,7 +4449,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 899d9ea8ed7a55f26b9b552fd5455e3b68ebda9b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 3151/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 8ac8eb6c38..a51cf3d119 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -138,6 +139,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 4f09090846bc4cf18b7f9c211ba848426f3a96ef Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 3152/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 1b2bf5fe66..b648c14a86 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -420,7 +420,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 366217b625e9a6d9fb63166959fd66c0130fd223 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 3153/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 643938d905..cda17f775a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -162,6 +163,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -172,6 +189,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->source.identifier))
+			continue;
+
 		opt->output_priv = w;
 		hit |= grep_source(opt, &w->source);
 		grep_source_clear_data(&w->source);
@@ -418,6 +438,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -883,6 +906,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From cfb60bacd979c87783d3d32bf46351083ec95ea1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 3154/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 073c3f67e6..c7c90e5f33 100644
--- a/Makefile
+++ b/Makefile
@@ -308,7 +308,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From ea3c194394e22d7a702d514ab14cf776bae86f66 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 3155/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index fe3cae3a38..f86800680c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 2a1517684caeddfb08481d03f0a042d5db8a1f8e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 3156/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c7c90e5f33..5223417b99 100644
--- a/Makefile
+++ b/Makefile
@@ -2093,7 +2093,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2133,6 +2133,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 82c010fec809c5ba005a596859b838af5f301a89 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 3157/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..18a93cba9f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 17706a5251d9e1259d6c4597909bdbfa999b28d8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 3158/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index cda17f775a..3af417e76c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -974,6 +974,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From 53c28ba0e950d41f24bf54fba49d3b85f30d6caa Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 3159/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index f7ce511bbb..62fda029e8 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 14a05feb2946269291cee0ffcf956a79d2110c22 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 3160/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f86800680c..61a1230433 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From be27c9fcc3c19d1d9e0f67e7a8c33747e68236be Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 3161/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From dff7bef7b6d838ec09818e38173a4bdd6b6192a0 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 3162/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 3163/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index efc86ad4e0..5bec652114 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -832,12 +832,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 3164/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 433d72788f7497282394efb7c21f14e71b855e5a Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 3165/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 5d8e4e6c89..d9fc4be050 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 3166/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 5223417b99..7879caa174 100644
--- a/Makefile
+++ b/Makefile
@@ -1188,6 +1188,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1281,6 +1282,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 09a30e66b368345a1b1d938b17cc5c1f998956b3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 3167/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From ecf078d458935f43857a92e386073d0b5bd76f9e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 3168/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From 86b0ab5104c9b76cbe1600bf32693cbf71e89a53 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 3169/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 63dcaff1f4db6398376f96283fcf67ce4b17ce92 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 3170/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From f2d696c02b4e029fb003bd889f3fe5098f2963f5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 3171/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 61a1230433..398c11f175 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 8d36fb6ea48f2e5957da5a2ae1009727f8955cc7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 3172/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 398c11f175..8565118abd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 60e281a7fe..da9c53583a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 6c48bb1476740d1362d5699f357fb8f67e2b8c05 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 3173/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8565118abd..1b40ff2373 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From a63d86f149e7f434b672218b00ff024644dfb520 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 3174/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 3c2284f611..e032b69aff 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6812,7 +6812,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6860,6 +6872,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From a04d32ad4b88c4484b6d537539f093503b9aa9b2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 3175/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e032b69aff..5dbbcfa0ba 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4434,7 +4434,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 9daad2fe9db682363213ead365ee5978dc8e16eb Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 3176/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 5dbbcfa0ba..14a133ae00 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6925,7 +6925,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From fc4d00986c4bf6c9e3cc47bcdfff25e22f9c69fa Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 3177/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1b40ff2373..952a2a6819 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From ebf8ea9c4fe8d3ada1095b9e12bf4a8647d71c41 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 3178/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index da9c53583a..1f9f35f63d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 08690a617f6b4d2d87c8e9183a4f39946f8c9d8b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 3179/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 2a10047eb7..be1b098be0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -113,7 +114,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -278,7 +284,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From cce0dad30bc054189ccf4d18af2b13540f57b75a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 3180/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 24a301f2d7..beaca417a9 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -699,6 +699,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index be1b098be0..34b47c4fb2 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 535fce56f714e2f760731faea00944b1d526ca23 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 3181/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1f9f35f63d..407bad231b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 39866a76c2..76c5eef420 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From 0f5e78091ad4bd338372d7cb493a7055024ae653 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 3182/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From cc7965f339b3921074720cca055f49d4df913a2c Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 3183/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 7879caa174..3ad3062305 100644
--- a/Makefile
+++ b/Makefile
@@ -1186,6 +1186,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From 2476b0c56b602f342408d611acb248e0f0f89f4c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 3184/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From 8ec6375188df0038ff5d92497a0fcc9f53d33316 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 3185/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3ad3062305..4dc9256967 100644
--- a/Makefile
+++ b/Makefile
@@ -1264,7 +1264,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From da0c9af43e402d6e80be5ea506bea75585021956 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 16:50:50 +0000
Subject: [PATCH 3186/3720] gitk: fix the display of files when filtered by
 path

Launching 'gitk -- .' or 'gitk -- ..\t' restricts the display to files
under the given directory but the file list is left empty. This is because
the path_filter function fails to match the filenames which are relative
to the working tree to the filter which is filessytem relative.
This solves the problem by making both names fully qualified filesystem
paths before performing the comparison.

Signed-off-by: Pat Thoyts 
Tested-by: David Aguilar 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 928a25d904..77c38b01b6 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -14,6 +14,26 @@ proc hasworktree {} {
 		  [exec git rev-parse --is-inside-git-dir] == "false"}]
 }
 
+proc gitworktree {} {
+    variable _gitworktree
+    if {[info exists _gitworktree]} {
+	return $_gitworktree
+    }
+    # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+    if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+        # try to set work tree from environment, core.worktree or use
+        # cdup to obtain a relative path to the top of the worktree. If
+        # run from the top, the ./ prefix ensures normalize expands pwd.
+        if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+	    catch {set _gitworktree [exec git config --get core.worktree]}
+	    if {$_gitworktree eq ""} {
+		set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+	    }
+        }
+    }
+    return $_gitworktree
+}
+
 # A simple scheduler for compute-intensive stuff.
 # The aim is to make sure that event handlers for GUI actions can
 # run at least every 50-100 ms.  Unfortunately fileevent handlers are
@@ -7393,19 +7413,15 @@ proc startdiff {ids} {
     }
 }
 
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
 proc path_filter {filter name} {
+    set worktree [gitworktree]
     foreach p $filter {
-	set l [string length $p]
-	if {[string index $p end] eq "/"} {
-	    if {[string compare -length $l $p $name] == 0} {
-		return 1
-	    }
-	} else {
-	    if {[string compare -length $l $p $name] == 0 &&
-		([string length $name] == $l ||
-		 [string index $name $l] eq "/")} {
-		return 1
-	    }
+	set fq_p [file normalize $p]
+	set fq_n [file normalize [file join $worktree $name]]
+	if {[string match [file normalize $fq_p]* $fq_n]} {
+	    return 1
 	}
     }
     return 0

From aac8c15cb8a9142a7b334c68d57cd6df93013cf6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 3187/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 4dc9256967..c82f297f0f 100644
--- a/Makefile
+++ b/Makefile
@@ -1301,6 +1301,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From 4e6eaeb16ba5b4749956046a9fdcb1e452c80c79 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 3188/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From 0e6d933142f5252261171d611fe36d12ecaa0943 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 6 Jan 2012 13:56:09 -0600
Subject: [PATCH 3189/3720] Install Git/I18N.pm even in the absence of Perl's
 MakeMaker

The telltale was that t0202 could not find I18N.pm on msysGit.

Signed-off-by: Johannes Schindelin 
---
 perl/Makefile | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/perl/Makefile b/perl/Makefile
index b2977cd0bc..91848f3d3c 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -24,13 +24,15 @@ ifdef NO_PERL_MAKEMAKER
 instdir_SQ = $(subst ','\'',$(prefix)/lib)
 $(makfile): ../GIT-CFLAGS Makefile
 	echo all: private-Error.pm Git.pm > $@
-	echo '	mkdir -p blib/lib' >> $@
+	echo '	mkdir -p blib/lib/Git' >> $@
+	echo '	$(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@
 	echo '	$(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@
 	echo '	$(RM) blib/lib/Error.pm' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
 	echo '	cp private-Error.pm blib/lib/Error.pm' >> $@
 	echo install: >> $@
-	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)"' >> $@
+	echo '	mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
+	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm "$$(DESTDIR)$(instdir_SQ)/Git/"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm "$$(DESTDIR)$(instdir_SQ)"' >> $@
 	echo '	$(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
 	'$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \

From 3325b5b07af1c472732e302d86e360e31ef47653 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 18:15:31 +0100
Subject: [PATCH 3190/3720] Windows/i18n: rename $path to prevent clashes with
 $PATH

Environment variables on Windows are case-insensitive. Rename '$path' in
all calls to eval_gettext to $modulepath so that it is not mistakenly
expanded to the value of the $PATH variable.

[jes: this happens to fix t7406/t7407 on Windows]
[pt: squashed in fix for substitution order error that broke t7400]

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
---
 git-submodule.sh | 52 ++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index dccd0f663a..efb0cfdfe9 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -105,7 +105,7 @@ module_name()
 	name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
 	test -z "$name" &&
-	die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+	die "$(modulepath=$path eval_gettext "No submodule mapping found in .gitmodules for path '\$modulepath'")"
 	echo "$name"
 }
 
@@ -146,7 +146,7 @@ module_clone()
 		mkdir -p "$gitdir_base"
 		git clone $quiet -n ${reference:+"$reference"} \
 			--separate-git-dir "$gitdir" "$url" "$path" ||
-		die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+		die "$(modulepath=$path eval_gettext "Clone of '\$url' into submodule path '\$modulepath' failed")"
 	fi
 
 	a=$(cd "$gitdir" && pwd)/
@@ -261,13 +261,13 @@ cmd_add()
 			s|/*$||
 		')
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
-	die "$(eval_gettext "'\$path' already exists in the index")"
+	die "$(modulepath=$path eval_gettext "'\$modulepath' already exists in the index")"
 
 	if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
 	then
 		cat >&2 </dev/null) &&
 					 test -z "$rev") || git-fetch)) ||
-				die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
+				die "$(modulepath=$path eval_gettext "Unable to fetch in submodule path '\$modulepath'")"
 			fi
 
 			# Is this something we just cloned?
@@ -564,20 +564,20 @@ Maybe you want to use 'update --init'?")"
 			case "$update_module" in
 			rebase)
 				command="git rebase"
-				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to rebase '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': rebased into '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			merge)
 				command="git merge"
-				die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to merge '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': merged in '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			*)
 				command="git checkout $subforce -q"
-				die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to checkout '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': checked out '\$sha1'")"
 				;;
 			esac
 
@@ -599,7 +599,7 @@ Maybe you want to use 'update --init'?")"
 			res=$?
 			if test $res -gt 0
 			then
-				die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+				die_msg="$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 				if test $res -eq 1
 				then
 					err="${err};$die_msg"
@@ -926,7 +926,7 @@ cmd_status()
 				cd "$path" &&
 				eval cmd_status "$orig_args"
 			) ||
-			die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+			die "$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 		fi
 	done
 }

From ad3e3a23abdc8412b16d37f0273653f035f31225 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 13 Dec 2011 14:56:49 +0000
Subject: [PATCH 3191/3720] gitk: use a tabbed dialog to edit preferences

This commit converts the user preferences dialog into a tabbed property
sheet grouping general properties, colours and font selections onto
separate pages. The previous implementation was exceeding the screen
height on some systems and this avoids such problems and permits extension
using new pages in the future.

If themed Tk is unavailable or undesired a reasonable facsimile of the
tabbed notebook widget is used instead.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 256 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 160 insertions(+), 96 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 77c38b01b6..dcae0a7547 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10805,6 +10805,139 @@ proc chg_fontparam {v sub op} {
     font config sample -$sub $fontparam($sub)
 }
 
+# Create a property sheet tab page
+proc create_prefs_page {w} {
+    global NS
+    set parent [join [lrange [split $w .] 0 end-1] .]
+    if {[winfo class $parent] eq "TNotebook"} {
+	${NS}::frame $w
+    } else {
+	${NS}::labelframe $w
+    }
+}
+
+proc prefspage_general {notebook} {
+    global NS maxwidth maxgraphpct showneartags showlocalchanges
+    global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
+    global hideremotes want_ttk have_ttk
+
+    set page [create_prefs_page $notebook.general]
+
+    ${NS}::label $page.ldisp -text [mc "Commit list display options"]
+    grid $page.ldisp - -sticky w -pady 10
+    ${NS}::label $page.spacer -text " "
+    ${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"]
+    spinbox $page.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+    grid $page.spacer $page.maxwidthl $page.maxwidth -sticky w
+    ${NS}::label $page.maxpctl -text [mc "Maximum graph width (% of pane)"]
+    spinbox $page.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+    grid x $page.maxpctl $page.maxpct -sticky w
+    ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \
+	-variable showlocalchanges
+    grid x $page.showlocal -sticky w
+    ${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \
+	-variable autoselect
+    spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
+    grid x $page.autoselect $page.autosellen -sticky w
+    ${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \
+	-variable hideremotes
+    grid x $page.hideremotes -sticky w
+
+    ${NS}::label $page.ddisp -text [mc "Diff display options"]
+    grid $page.ddisp - -sticky w -pady 10
+    ${NS}::label $page.tabstopl -text [mc "Tab spacing"]
+    spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
+    grid x $page.tabstopl $page.tabstop -sticky w
+    ${NS}::checkbutton $page.ntag -text [mc "Display nearby tags"] \
+	-variable showneartags
+    grid x $page.ntag -sticky w
+    ${NS}::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \
+	-variable limitdiffs
+    grid x $page.ldiff -sticky w
+    ${NS}::checkbutton $page.lattr -text [mc "Support per-file encodings"] \
+	-variable perfile_attrs
+    grid x $page.lattr -sticky w
+
+    ${NS}::entry $page.extdifft -textvariable extdifftool
+    ${NS}::frame $page.extdifff
+    ${NS}::label $page.extdifff.l -text [mc "External diff tool" ]
+    ${NS}::button $page.extdifff.b -text [mc "Choose..."] -command choose_extdiff
+    pack $page.extdifff.l $page.extdifff.b -side left
+    pack configure $page.extdifff.l -padx 10
+    grid x $page.extdifff $page.extdifft -sticky ew
+
+    ${NS}::label $page.lgen -text [mc "General options"]
+    grid $page.lgen - -sticky w -pady 10
+    ${NS}::checkbutton $page.want_ttk -variable want_ttk \
+	-text [mc "Use themed widgets"]
+    if {$have_ttk} {
+	${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
+    } else {
+	${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
+    }
+    grid x $page.want_ttk $page.ttk_note -sticky w
+    return $page
+}
+
+proc prefspage_colors {notebook} {
+    global NS uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+
+    set page [create_prefs_page $notebook.colors]
+
+    ${NS}::label $page.cdisp -text [mc "Colors: press to choose"]
+    grid $page.cdisp - -sticky w -pady 10
+    label $page.ui -padx 40 -relief sunk -background $uicolor
+    ${NS}::button $page.uibut -text [mc "Interface"] \
+       -command [list choosecolor uicolor {} $page.ui [mc "interface"] setui]
+    grid x $page.uibut $page.ui -sticky w
+    label $page.bg -padx 40 -relief sunk -background $bgcolor
+    ${NS}::button $page.bgbut -text [mc "Background"] \
+	-command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
+    grid x $page.bgbut $page.bg -sticky w
+    label $page.fg -padx 40 -relief sunk -background $fgcolor
+    ${NS}::button $page.fgbut -text [mc "Foreground"] \
+	-command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
+    grid x $page.fgbut $page.fg -sticky w
+    label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
+    ${NS}::button $page.diffoldbut -text [mc "Diff: old lines"] \
+	-command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
+		      [list $ctext tag conf d0 -foreground]]
+    grid x $page.diffoldbut $page.diffold -sticky w
+    label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
+    ${NS}::button $page.diffnewbut -text [mc "Diff: new lines"] \
+	-command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
+		      [list $ctext tag conf dresult -foreground]]
+    grid x $page.diffnewbut $page.diffnew -sticky w
+    label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
+    ${NS}::button $page.hunksepbut -text [mc "Diff: hunk header"] \
+	-command [list choosecolor diffcolors 2 $page.hunksep \
+		      [mc "diff hunk header"] \
+		      [list $ctext tag conf hunksep -foreground]]
+    grid x $page.hunksepbut $page.hunksep -sticky w
+    label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor
+    ${NS}::button $page.markbgbut -text [mc "Marked line bg"] \
+	-command [list choosecolor markbgcolor {} $page.markbgsep \
+		      [mc "marked line background"] \
+		      [list $ctext tag conf omark -background]]
+    grid x $page.markbgbut $page.markbgsep -sticky w
+    label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor
+    ${NS}::button $page.selbgbut -text [mc "Select bg"] \
+	-command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
+    grid x $page.selbgbut $page.selbgsep -sticky w
+    return $page
+}
+
+proc prefspage_fonts {notebook} {
+    global NS
+    set page [create_prefs_page $notebook.fonts]
+    ${NS}::label $page.cfont -text [mc "Fonts: press to choose"]
+    grid $page.cfont - -sticky w -pady 10
+    mkfontdisp mainfont $page [mc "Main font"]
+    mkfontdisp textfont $page [mc "Diff display font"]
+    mkfontdisp uifont $page [mc "User interface font"]
+    return $page
+}
+
 proc doprefs {} {
     global maxwidth maxgraphpct use_ttk NS
     global oldprefs prefstop showneartags showlocalchanges
@@ -10825,106 +10958,37 @@ proc doprefs {} {
     ttk_toplevel $top
     wm title $top [mc "Gitk preferences"]
     make_transient $top .
-    ${NS}::label $top.ldisp -text [mc "Commit list display options"]
-    grid $top.ldisp - -sticky w -pady 10
-    ${NS}::label $top.spacer -text " "
-    ${NS}::label $top.maxwidthl -text [mc "Maximum graph width (lines)"]
-    spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
-    grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
-    ${NS}::label $top.maxpctl -text [mc "Maximum graph width (% of pane)"]
-    spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
-    grid x $top.maxpctl $top.maxpct -sticky w
-    ${NS}::checkbutton $top.showlocal -text [mc "Show local changes"] \
-	-variable showlocalchanges
-    grid x $top.showlocal -sticky w
-    ${NS}::checkbutton $top.autoselect -text [mc "Auto-select SHA1 (length)"] \
-	-variable autoselect
-    spinbox $top.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
-    grid x $top.autoselect $top.autosellen -sticky w
-    ${NS}::checkbutton $top.hideremotes -text [mc "Hide remote refs"] \
-	-variable hideremotes
-    grid x $top.hideremotes -sticky w
 
-    ${NS}::label $top.ddisp -text [mc "Diff display options"]
-    grid $top.ddisp - -sticky w -pady 10
-    ${NS}::label $top.tabstopl -text [mc "Tab spacing"]
-    spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
-    grid x $top.tabstopl $top.tabstop -sticky w
-    ${NS}::checkbutton $top.ntag -text [mc "Display nearby tags"] \
-	-variable showneartags
-    grid x $top.ntag -sticky w
-    ${NS}::checkbutton $top.ldiff -text [mc "Limit diffs to listed paths"] \
-	-variable limitdiffs
-    grid x $top.ldiff -sticky w
-    ${NS}::checkbutton $top.lattr -text [mc "Support per-file encodings"] \
-	-variable perfile_attrs
-    grid x $top.lattr -sticky w
-
-    ${NS}::entry $top.extdifft -textvariable extdifftool
-    ${NS}::frame $top.extdifff
-    ${NS}::label $top.extdifff.l -text [mc "External diff tool" ]
-    ${NS}::button $top.extdifff.b -text [mc "Choose..."] -command choose_extdiff
-    pack $top.extdifff.l $top.extdifff.b -side left
-    pack configure $top.extdifff.l -padx 10
-    grid x $top.extdifff $top.extdifft -sticky ew
-
-    ${NS}::label $top.lgen -text [mc "General options"]
-    grid $top.lgen - -sticky w -pady 10
-    ${NS}::checkbutton $top.want_ttk -variable want_ttk \
-	-text [mc "Use themed widgets"]
-    if {$have_ttk} {
-	${NS}::label $top.ttk_note -text [mc "(change requires restart)"]
+    if {[set use_notebook [expr {$use_ttk && [info command ::ttk::notebook] ne ""}]]} {
+	set notebook [ttk::notebook $top.notebook]
     } else {
-	${NS}::label $top.ttk_note -text [mc "(currently unavailable)"]
+	set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat]
     }
-    grid x $top.want_ttk $top.ttk_note -sticky w
 
-    ${NS}::label $top.cdisp -text [mc "Colors: press to choose"]
-    grid $top.cdisp - -sticky w -pady 10
-    label $top.ui -padx 40 -relief sunk -background $uicolor
-    ${NS}::button $top.uibut -text [mc "Interface"] \
-       -command [list choosecolor uicolor {} $top.ui [mc "interface"] setui]
-    grid x $top.uibut $top.ui -sticky w
-    label $top.bg -padx 40 -relief sunk -background $bgcolor
-    ${NS}::button $top.bgbut -text [mc "Background"] \
-	-command [list choosecolor bgcolor {} $top.bg [mc "background"] setbg]
-    grid x $top.bgbut $top.bg -sticky w
-    label $top.fg -padx 40 -relief sunk -background $fgcolor
-    ${NS}::button $top.fgbut -text [mc "Foreground"] \
-	-command [list choosecolor fgcolor {} $top.fg [mc "foreground"] setfg]
-    grid x $top.fgbut $top.fg -sticky w
-    label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
-    ${NS}::button $top.diffoldbut -text [mc "Diff: old lines"] \
-	-command [list choosecolor diffcolors 0 $top.diffold [mc "diff old lines"] \
-		      [list $ctext tag conf d0 -foreground]]
-    grid x $top.diffoldbut $top.diffold -sticky w
-    label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
-    ${NS}::button $top.diffnewbut -text [mc "Diff: new lines"] \
-	-command [list choosecolor diffcolors 1 $top.diffnew [mc "diff new lines"] \
-		      [list $ctext tag conf dresult -foreground]]
-    grid x $top.diffnewbut $top.diffnew -sticky w
-    label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
-    ${NS}::button $top.hunksepbut -text [mc "Diff: hunk header"] \
-	-command [list choosecolor diffcolors 2 $top.hunksep \
-		      [mc "diff hunk header"] \
-		      [list $ctext tag conf hunksep -foreground]]
-    grid x $top.hunksepbut $top.hunksep -sticky w
-    label $top.markbgsep -padx 40 -relief sunk -background $markbgcolor
-    ${NS}::button $top.markbgbut -text [mc "Marked line bg"] \
-	-command [list choosecolor markbgcolor {} $top.markbgsep \
-		      [mc "marked line background"] \
-		      [list $ctext tag conf omark -background]]
-    grid x $top.markbgbut $top.markbgsep -sticky w
-    label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
-    ${NS}::button $top.selbgbut -text [mc "Select bg"] \
-	-command [list choosecolor selectbgcolor {} $top.selbgsep [mc "background"] setselbg]
-    grid x $top.selbgbut $top.selbgsep -sticky w
+    lappend pages [prefspage_general $notebook] [mc "General"]
+    lappend pages [prefspage_colors $notebook] [mc "Colors"]
+    lappend pages [prefspage_fonts $notebook] [mc "Fonts"]
+    foreach {page title} $pages {
+	if {$use_notebook} {
+	    $notebook add $page -text $title
+	} else {
+	    set btn [${NS}::button $notebook.b_[string map {. X} $page] \
+			 -text $title -command [list raise $page]]
+	    $page configure -text $title
+	    grid $btn -row 0 -column [incr col] -sticky w
+	    grid $page -row 1 -column 0 -sticky news -columnspan 100
+	}
+    }
 
-    ${NS}::label $top.cfont -text [mc "Fonts: press to choose"]
-    grid $top.cfont - -sticky w -pady 10
-    mkfontdisp mainfont $top [mc "Main font"]
-    mkfontdisp textfont $top [mc "Diff display font"]
-    mkfontdisp uifont $top [mc "User interface font"]
+    if {!$use_notebook} {
+	grid columnconfigure $notebook 0 -weight 1
+	grid rowconfigure $notebook 1 -weight 1
+	raise [lindex $pages 0]
+    }
+
+    grid $notebook -sticky news -padx 2 -pady 2
+    grid rowconfigure $top 0 -weight 1
+    grid columnconfigure $top 0 -weight 1
 
     ${NS}::frame $top.buts
     ${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active
@@ -10936,7 +11000,7 @@ proc doprefs {} {
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
     grid $top.buts - - -pady 10 -sticky ew
     grid columnconfigure $top 2 -weight 1
-    bind $top  "focus $top.buts.ok"
+    bind $top  [list focus $top.buts.ok]
 }
 
 proc choose_extdiff {} {

From d07340a57e3859c13819d24c7b0dd4393dc9e638 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Mon, 30 Jan 2012 23:38:42 +0000
Subject: [PATCH 3192/3720] gitk: fix setting font display with new tabbed
 dialog layout.

The changes to the dialog window tree broke the preview of the selected
font on the button. This corrects that issue.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index dcae0a7547..a62f25d549 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10751,7 +10751,7 @@ proc fontok {} {
     if {$fontparam(slant) eq "italic"} {
 	lappend fontpref($f) "italic"
     }
-    set w $prefstop.$f
+    set w $prefstop.notebook.fonts.$f
     $w conf -text $fontparam(family) -font $fontpref($f)
 
     fontcan

From de1489f383f61d820548e6b293a2d145f081010c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 3 Feb 2012 00:12:04 -0600
Subject: [PATCH 3193/3720] Teach 'git remote' that the config var
 branch.*.rebase can be 'interactive'

Signed-off-by: Johannes Schindelin 
---
 builtin/remote.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index fec92bc66e..7b37a23d97 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -253,7 +253,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	int rebase;
+	enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
 };
 
 static struct string_list branch_list;
@@ -310,7 +310,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			}
 			string_list_append(&info->merge, xstrdup(value));
 		} else
-			info->rebase = git_config_bool(orig_key, value);
+			info->rebase = value && *value == 'i' ?
+				INTERACTIVE_REBASE :
+				(git_config_bool(orig_key, value) ?
+				 NORMAL_REBASE : NO_REBASE);
 	}
 	return 0;
 }
@@ -994,7 +997,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf("rebases onto remote %s\n", merge->items[0].string);
+		printf("rebases %sonto remote %s\n",
+			branch_info->rebase == INTERACTIVE_REBASE ?
+			"interactively " : "", merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf(" merges with remote %s\n", merge->items[0].string);

From 64e875e84f093a6ace0c3b1ad01df7bbb5a77035 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:28:37 +0100
Subject: [PATCH 3194/3720] git-gui: fix encoding in git-gui file browser

Assume git tree objects (i.e. output of git-ls-tree) are encoded in system
encoding, for display in the git-gui file browser.

Signed-off-by: Karsten Blees 
---
 git-gui/lib/browser.tcl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 0328338fda..4fca8fb13c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary -encoding binary
+	fconfigure $fd -blocking 0 -translation binary
 	fileevent $fd readable [cb _read $fd]
 }
 

From 44fcc169fbb827d89826c0f3200592460470e071 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:38:07 +0100
Subject: [PATCH 3195/3720] gitk: fix file name encoding in diff hunk headers

Decode file names from system encoding in all diff hunk header lines, not
just the first (i.e. print nice file names in 'rename from' / 'rename to' /
'Binary files' lines, too).

Signed-off-by: Karsten Blees 
---
 gitk-git/gitk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index a62f25d549..3660096db5 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7811,6 +7811,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
+	    set line [encoding convertfrom $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {

From f09e267a8e624035d49d53c5edd9401d27ee166f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 19:06:41 +0100
Subject: [PATCH 3196/3720] Revert "Windows: teach getenv to do a
 case-sensitive search"

This reverts commit df599e9612788b728ce43a03159b85f1fe624d6a.

As of 5e9637c6 "i18n: add infrastructure for translating Git with gettext",
eval_gettext uses MinGW envsubst.exe instead of git-sh-i18n--envsubst.exe
for variable substitution. This breaks git-submodule.sh messages and tests,
as envsubst.exe doesn't support case-sensitive environment lookup (the same
is true for almost everything on Windows, including MSys and Cygwin tools).

30a615ac "Windows/i18n: rename $path to prevent clashes with $PATH" renames
the conflicting variable in git-submodule.sh, so that it works on Windows
(i.e. with case-insensitive environment, regardless of the toolset).

Revert to the documented behaviour of case-insensitive environment on
Windows.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 952a2a6819..1135b4bb78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1182,31 +1182,14 @@ char **make_augmented_environ(const char *const *vars)
 }
 
 #undef getenv
-
-/*
- * The system's getenv looks up the name in a case-insensitive manner.
- * This version tries a case-sensitive lookup and falls back to
- * case-insensitive if nothing was found.  This is necessary because,
- * as a prominent example, CMD sets 'Path', but not 'PATH'.
- * Warning: not thread-safe.
- */
-static char *getenv_cs(const char *name)
-{
-	size_t len = strlen(name);
-	int i = lookup_env(environ, name, len);
-	if (i >= 0)
-		return environ[i] + len + 1;	/* skip past name and '=' */
-	return getenv(name);
-}
-
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv_cs(name);
+	char *result = getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv_cs("TMP");
+		result = getenv("TMP");
 		if (!result)
-			result = getenv_cs("TEMP");
+			result = getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */

From fb0fd4cb41cc293fd9641a1b0eda4165e6610008 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:19:31 +0100
Subject: [PATCH 3197/3720] Revert "mingw.c: move definition of mingw_getenv
 down"

This reverts commit 06bc4b796ad69ba93f0a8c451368602e0553c2d3.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1135b4bb78..649c6857dd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -180,7 +180,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	vsnprintf(question, sizeof(question), format, args);
 	va_end(args);
 
-	if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
+	if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
 		retry_hook[1] = question;
 		return !run_command_v_opt(retry_hook, 0);
 	}
@@ -665,6 +665,23 @@ char *mingw_getcwd(char *pointer, int len)
 	return ret;
 }
 
+#undef getenv
+char *mingw_getenv(const char *name)
+{
+	char *result = getenv(name);
+	if (!result && !strcmp(name, "TMPDIR")) {
+		/* on Windows it is TMP and TEMP */
+		result = getenv("TMP");
+		if (!result)
+			result = getenv("TEMP");
+	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
+	return result;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -764,7 +781,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-	char *p, **path, *envpath = mingw_getenv("PATH");
+	char *p, **path, *envpath = getenv("PATH");
 	int i, n = 0;
 
 	if (!envpath || !*envpath)
@@ -1181,23 +1198,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-	char *result = getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
-		if (!result)
-			result = getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 07089da06aabc1a22f29dccc948b7c928c0f9b3d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:24:19 +0100
Subject: [PATCH 3198/3720] Win32: Thread-safe windows console output

Winansi.c has many static variables that are accessed and modified from
the [v][f]printf / fputs functions overridden in the file. This may cause
multi threaded git commands that print to the console to produce corrupted
output or even crash.

Additionally, winansi.c doesn't override all functions that can be used to
print to the console (e.g. fwrite, write, fputc are missing), so that ANSI
escapes don't work properly for some git commands (e.g. git-grep).

Instead of doing ANSI emulation in just a few wrapped functions on top of
the IO API, let's plug into the IO system and take advantage of the thread
safety inherent to the IO system.

Redirect stdout and stderr to a pipe if they point to the console. A
background thread reads from the pipe, handles ANSI escape sequences and
UTF-8 to UTF-16 conversion, then writes to the console.

The pipe-based stdout and stderr replacements must be set to unbuffered, as
MSVCRT doesn't support line buffering and fully buffered streams are
inappropriate for console output.

Due to the byte-oriented pipe, ANSI escape sequences and multi-byte UTF-8
sequences can no longer be expected to arrive in one piece. Replace the
string-based ansi_emulate() with a simple stateful parser (this also fixes
colored diff hunk headers, which were broken as of commit 2efcc977).

Override isatty to return true for the pipes redirecting to the console.

Exec/spawn obtain the original console handle to pass to the next process
via winansi_get_osfhandle().

All other overrides are gone, the default stdio implementations work as
expected with the piped stdout/stderr descriptors.

Global variables are either initialized on startup (single threaded) or
exclusively modified by the background thread. Threads communicate through
the pipe, no further synchronization is necessary.

The background thread is terminated by disonnecting the pipe after flushing
the stdio and pipe buffers. This doesn't work for anonymous pipes (created
via CreatePipe), as DisconnectNamedPipe only works on the read end, which
discards remaining data. Thus we have to setup the pipe manually, with the
write end beeing the server (opened with CreateNamedPipe) and the read end
the client (opened with CreateFile).

Limitations: doesn't track reopened or duped file descriptors, i.e.:
- fdopen(1/2) returns fully buffered streams
- dup(1/2), dup2(1/2) returns normal pipe descriptors (i.e. isatty() =
  false, winansi_get_osfhandle won't return the original console handle)

Currently, only the git-format-patch command uses xfdopen(xdup(1)) (see
"realstdout" in builtin/log.c), but works well with these limitations.

Many thanks to Atsushi Nakagawa  for suggesting and
reviewing the thread-exit-mechanism.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c   |   9 +-
 compat/mingw.h   |  12 +-
 compat/winansi.c | 420 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 282 insertions(+), 159 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 649c6857dd..190e7b7681 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -917,9 +917,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	memset(&si, 0, sizeof(si));
 	si.cb = sizeof(si);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-	si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-	si.hStdError = (HANDLE) _get_osfhandle(fherr);
+	si.hStdInput = winansi_get_osfhandle(fhin);
+	si.hStdOutput = winansi_get_osfhandle(fhout);
+	si.hStdError = winansi_get_osfhandle(fherr);
 
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
@@ -1878,4 +1878,7 @@ void mingw_startup()
 	_setmode(_fileno(stdin), _O_BINARY);
 	_setmode(_fileno(stdout), _O_BINARY);
 	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
 }
diff --git a/compat/mingw.h b/compat/mingw.h
index 407bad231b..2683adcaf7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -288,14 +288,10 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-int winansi_vfprintf(FILE *stream, const char *format, va_list list);
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
-#define vfprintf winansi_vfprintf
+void winansi_init(void);
+int winansi_isatty(int fd);
+HANDLE winansi_get_osfhandle(int fd);
+#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index bec6713b74..a3e4d88295 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,18 +4,13 @@
 
 #undef NOGDI
 #include "../git-compat-util.h"
-#include 
 #include 
 #include 
 
 /*
  Functions to be wrapped:
 */
-#undef printf
-#undef fprintf
-#undef fputs
-#undef vfprintf
-/* TODO: write */
+#undef isatty
 
 /*
  ANSI codes used by git: m, K
@@ -28,7 +23,10 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
-static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hwrite1 = INVALID_HANDLE_VALUE, hwrite2 = INVALID_HANDLE_VALUE;
+static HANDLE hconsole1, hconsole2;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -44,27 +42,19 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void print_font_warning(void)
+static void warn_if_raster_font(void)
 {
-	warning("Your console font probably doesn\'t support Unicode. If "
-		"you experience strange characters in the output, consider "
-		"switching to a TrueType font such as Lucida Console!");
-}
-
-static void check_truetype_font(void)
-{
-	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't do this twice */
-	if (truetype_font_checked)
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
 		return;
-	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
+			GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);
@@ -73,8 +63,8 @@ static void check_truetype_font(void)
 	} else {
 		/* pre-Vista: check default console font in registry */
 		HKEY hkey;
-		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
-				KEY_READ, &hkey)) {
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+				0, KEY_READ, &hkey)) {
 			DWORD size = sizeof(fontFamily);
 			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
 					(LPVOID) &fontFamily, &size);
@@ -82,61 +72,63 @@ static void check_truetype_font(void)
 		}
 	}
 
-	if (!(fontFamily & TMPF_TRUETYPE))
-		atexit(print_font_warning);
+	if (!(fontFamily & TMPF_TRUETYPE)) {
+		const wchar_t *msg = L"\nWarning: Your console font probably "
+			L"doesn\'t support Unicode. If you experience strange "
+			L"characters in the output, consider switching to a "
+			L"TrueType font such as Lucida Console!\n";
+		WriteConsoleW(console, msg, wcslen(msg), NULL, NULL);
+	}
 }
 
-static int is_console(FILE *stream)
+static int is_console(int fd)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
 	HANDLE hcon;
 
 	static int initialized = 0;
 
-	/* use cached value if stream hasn't changed */
-	if (stream == last_stream)
-		return console != NULL;
-
-	last_stream = stream;
-	console = NULL;
-
-	/* get OS handle of the stream */
-	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	/* get OS handle of the file descriptor */
+	hcon = (HANDLE) _get_osfhandle(fd);
 	if (hcon == INVALID_HANDLE_VALUE)
 		return 0;
 
+	/* check if its a device (i.e. console, printer, serial port) */
+	if (GetFileType(hcon) != FILE_TYPE_CHAR)
+		return 0;
+
 	/* check if its a handle to a console output screen buffer */
 	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
+	/* initialize attributes */
 	if (!initialized) {
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
 	}
 
-	console = hcon;
 	return 1;
 }
 
-static int write_console(const char *str, size_t len)
-{
-	/* convert utf-8 to utf-16, write directly to console */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
-	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
-	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
 
+static void write_console(unsigned char *str, size_t len)
+{
+	/* only called from console_thread, so a static buffer will do */
+	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+
+	/* convert utf-8 to utf-16 */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
+			ARRAY_SIZE(wbuf));
+
+	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/*
-	 * if non-ascii characters are printed, check that the current console
-	 * font supports this
-	 */
+	/* remember if non-ascii characters are printed */
 	if (wlen != len)
-		check_truetype_font();
-
-	/* return original (utf-8 encoded) length */
-	return len;
+		non_ascii_used = 1;
 }
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
@@ -182,18 +174,13 @@ static void erase_in_line(void)
 		&dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-	const char *func;
-	size_t len = strspn(str, "0123456789;");
-	func = str + len;
-
-	switch (*func) {
+	int i;
+	switch (func) {
 	case 'm':
-		do {
-			long val = strtol(str, (char **)&str, 10);
-			switch (val) {
+		for (i = 0; i < paramlen; i++) {
+			switch (params[i]) {
 			case 0: /* reset */
 				attr = plain_attr;
 				negative = 0;
@@ -316,9 +303,7 @@ static const char *set_attr(const char *str)
 				/* Unsupported code */
 				break;
 			}
-			str++;
-		} while (*(str-1) == ';');
-
+		}
 		set_console_attr();
 		break;
 	case 'K':
@@ -328,112 +313,251 @@ static const char *set_attr(const char *str)
 		/* Unsupported code */
 		break;
 	}
-
-	return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+	TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-	int rv = 0;
-	const char *pos = str;
+	unsigned char buffer[BUFFER_SIZE];
+	DWORD bytes;
+	int start, end = 0, c, parampos = 0, state = TEXT;
+	int params[MAX_PARAMS];
 
-	fflush(stream);
+	while (1) {
+		/* read next chunk of bytes from the pipe */
+		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+				NULL)) {
+			/* exit if pipe has been closed or disconnected */
+			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+					GetLastError() == ERROR_BROKEN_PIPE)
+				break;
+			/* ignore other errors */
+			continue;
+		}
 
-	while (*pos) {
-		pos = strstr(str, "\033[");
-		if (pos) {
-			size_t len = pos - str;
+		/* scan the bytes and handle ANSI control codes */
+		bytes += end;
+		start = end = 0;
+		while (end < bytes) {
+			c = buffer[end++];
+			switch (state) {
+			case TEXT:
+				if (c == ESCAPE) {
+					/* print text seen so far */
+					if (end - 1 > start)
+						write_console(buffer + start,
+							end - 1 - start);
 
-			if (len) {
-				size_t out_len = write_console(str, len);
-				rv += out_len;
-				if (out_len < len)
-					return rv;
+					/* then start parsing escape sequence */
+					start = end - 1;
+					memset(params, 0, sizeof(params));
+					parampos = 0;
+					state = ESCAPE;
+				}
+				break;
+
+			case ESCAPE:
+				/* continue if "\033[", otherwise bail out */
+				state = (c == BRACKET) ? BRACKET : TEXT;
+				break;
+
+			case BRACKET:
+				/* parse [0-9;]* into array of parameters */
+				if (c >= '0' && c <= '9') {
+					params[parampos] *= 10;
+					params[parampos] += c - '0';
+				} else if (c == ';') {
+					/*
+					 * next parameter, bail out if out of
+					 * bounds
+					 */
+					parampos++;
+					if (parampos >= MAX_PARAMS)
+						state = TEXT;
+				} else {
+					/*
+					 * end of escape sequence, change
+					 * console attributes
+					 */
+					set_attr(c, params, parampos + 1);
+					start = end;
+					state = TEXT;
+				}
+				break;
+			}
+		}
+
+		/* print remaining text unless parsing an escape sequence */
+		if (state == TEXT && end > start) {
+			/* check for incomplete UTF-8 sequences and fix end */
+			if (buffer[end - 1] >= 0x80) {
+				if (buffer[end -1] >= 0xc0)
+					end--;
+				else if (end - 1 > start &&
+						buffer[end - 2] >= 0xe0)
+					end -= 2;
+				else if (end - 2 > start &&
+						buffer[end - 3] >= 0xf0)
+					end -= 3;
 			}
 
-			str = pos + 2;
-			rv += 2;
+			/* print remaining complete UTF-8 sequences */
+			if (end > start)
+				write_console(buffer + start, end - start);
 
-			pos = set_attr(str);
-			rv += pos - str;
-			str = pos;
+			/* move remaining bytes to the front */
+			if (end < bytes)
+				memmove(buffer, buffer + end, bytes - end);
+			end = bytes - end;
 		} else {
-			size_t len = strlen(str);
-			rv += write_console(str, len);
-			return rv;
+			/* all data has been consumed, mark buffer empty */
+			end = 0;
 		}
 	}
-	return rv;
+
+	/* check if the console font supports unicode */
+	warn_if_raster_font();
+
+	CloseHandle(hread);
+	return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-	int rv;
+	/* flush all streams */
+	_flushall();
 
-	if (!is_console(stream))
-		return fputs(str, stream);
+	/* signal console thread to exit */
+	FlushFileBuffers(hwrite);
+	DisconnectNamedPipe(hwrite);
 
-	rv = ansi_emulate(str, stream);
+	/* wait for console thread to copy remaining data */
+	WaitForSingleObject(hthread, INFINITE);
 
-	if (rv >= 0)
-		return 0;
+	/* cleanup handles... */
+	if (hwrite1 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite1);
+	if (hwrite2 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite2);
+	CloseHandle(hwrite);
+	CloseHandle(hthread);
+}
+
+static void die_lasterr(const char *fmt, ...)
+{
+	va_list params;
+	va_start(params, fmt);
+	errno = err_win_to_posix(GetLastError());
+	die_errno(fmt, params);
+	va_end(params);
+}
+
+static HANDLE duplicate_handle(HANDLE hnd)
+{
+	HANDLE hresult, hproc = GetCurrentProcess();
+	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+			DUPLICATE_SAME_ACCESS))
+		die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+	return hresult;
+}
+
+static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+{
+	/* get original console handle */
+	int fd = _fileno(stream);
+	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
+	if (hcon == INVALID_HANDLE_VALUE)
+		die_errno("_get_osfhandle(%i) failed", fd);
+
+	/* save a copy to phcon and console (used by the background thread) */
+	console = *phcon = duplicate_handle(hcon);
+
+	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
+	if (_dup2(new_fd, fd))
+		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+
+	/* no buffering, or stdout / stderr will be out of sync */
+	setbuf(stream, NULL);
+	return (HANDLE) _get_osfhandle(fd);
+}
+
+void winansi_init(void)
+{
+	int con1, con2, hwrite_fd;
+	char name[32];
+
+	/* check if either stdout or stderr is a console output screen buffer */
+	con1 = is_console(1);
+	con2 = is_console(2);
+	if (!con1 && !con2)
+		return;
+
+	/* create a named pipe to communicate with the console thread */
+	sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+	hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+	if (hwrite == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateNamedPipe failed");
+
+	hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (hread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateFile for named pipe failed");
+
+	/* start console spool thread on the pipe's read end */
+	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+	if (hthread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateThread(console_thread) failed");
+
+	/* schedule cleanup routine */
+	if (atexit(winansi_exit))
+		die_errno("atexit(winansi_exit) failed");
+
+	/* create a file descriptor for the write end of the pipe */
+	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
+	if (hwrite_fd == -1)
+		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
+
+	/* redirect stdout / stderr to the pipe */
+	if (con1)
+		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+	if (con2)
+		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
+
+	/* close pipe file descriptor (also closes the duped hwrite) */
+	close(hwrite_fd);
+}
+
+static int is_same_handle(HANDLE hnd, int fd)
+{
+	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
+}
+
+/*
+ * Return true if stdout / stderr is a pipe redirecting to the console.
+ */
+int winansi_isatty(int fd)
+{
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return 1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return 1;
 	else
-		return EOF;
+		return isatty(fd);
 }
 
-int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-	int len, rv;
-	char small_buf[256];
-	char *buf = small_buf;
-	va_list cp;
-
-	if (!is_console(stream))
-		goto abort;
-
-	va_copy(cp, list);
-	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-	va_end(cp);
-
-	if (len > sizeof(small_buf) - 1) {
-		buf = malloc(len + 1);
-		if (!buf)
-			goto abort;
-
-		len = vsnprintf(buf, len + 1, format, list);
-	}
-
-	rv = ansi_emulate(buf, stream);
-
-	if (buf != small_buf)
-		free(buf);
-	return rv;
-
-abort:
-	rv = vfprintf(stream, format, list);
-	return rv;
-}
-
-int winansi_fprintf(FILE *stream, const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stream, format, list);
-	va_end(list);
-
-	return rv;
-}
-
-int winansi_printf(const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stdout, format, list);
-	va_end(list);
-
-	return rv;
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return hconsole1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return hconsole2;
+	else
+		return (HANDLE) _get_osfhandle(fd);
 }

From 7f90208cc24520f14f0cdfe022323ac07b84020d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:05:06 +0100
Subject: [PATCH 3199/3720] Win32: add Unicode conversion functions

Add Unicode conversion functions to convert between Windows native UTF-16LE
encoding to UTF-8 and back.

To support repositories with legacy-encoded file names, the UTF-8 to UTF-16
conversion function tries to create valid, unique file names even for
invalid UTF-8 byte sequences, so that these repositories can be checked out
without error.

The current implementation leaves invalid UTF-8 bytes in range 0xa0 - 0xff
as is (producing printable Unicode chars \u00a0 - \u00ff, equivalent to
ISO-8859-1), and converts 0x80 - 0x9f to hex-code (\u0080 - \u009f are
control chars).

The Windows MultiByteToWideChar API was not used as it either drops invalid
UTF-8 sequences (on Win2k/XP; producing non-unique or even empty file
names) or converts them to the replacement char \ufffd (Vista/7; causing
ERROR_INVALID_NAME in subsequent calls to file system APIs).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c |  85 ++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 190e7b7681..8ed43f9bf1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1859,6 +1859,91 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
diff --git a/compat/mingw.h b/compat/mingw.h
index 2683adcaf7..ddb228473b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -326,6 +326,110 @@ void mingw_mark_as_git_dir(const char *dir);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A replacement of main() that adds win32 specific initialization.
  */

From 0db8d27047a73d0997a8f534b1be38ab665ae3d3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 18:21:28 +0100
Subject: [PATCH 3200/3720] Win32: Unicode file name support (except dirent)

Replaces Windows "ANSI" APIs dealing with file- or path names with their
Unicode equivalent, adding UTF-8/UTF-16LE conversion as necessary.

The dirent API (opendir/readdir/closedir) is updated in a separate commit.

Adds trivial wrappers for access, chmod and chdir.

Adds wrapper for mktemp (needed for both mkstemp and mkdtemp).

The simplest way to convert a repository with legacy-encoded (e.g. Cp1252)
file names to UTF-8 ist to checkout with an old msysgit version and
"git add --all & git commit" with the new version.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 210 ++++++++++++++++++++++++++++++++++---------------
 compat/mingw.h |  13 +++
 2 files changed, 158 insertions(+), 65 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8ed43f9bf1..5d5f30bd2c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "win32.h"
 #include 
+#include 
 #include "../strbuf.h"
 #include "../run-command.h"
 #include "../cache.h"
@@ -200,14 +201,16 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	}
 }
 
-#undef unlink
 int mingw_unlink(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
 	/* read-only files cannot be removed */
-	chmod(pathname, 0666);
-	while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
 		/*
@@ -223,43 +226,40 @@ int mingw_unlink(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = unlink(pathname);
+	       ret = _wunlink(wpathname);
 	return ret;
 }
 
-static int is_dir_empty(const char *path)
+static int is_dir_empty(const wchar_t *wpath)
 {
-	struct strbuf buf = STRBUF_INIT;
-	WIN32_FIND_DATAA findbuf;
+	WIN32_FIND_DATAW findbuf;
 	HANDLE handle;
-
-	strbuf_addf(&buf, "%s\\*", path);
-	handle = FindFirstFileA(buf.buf, &findbuf);
-	if (handle == INVALID_HANDLE_VALUE) {
-		strbuf_release(&buf);
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
 		return GetLastError() == ERROR_NO_MORE_FILES;
-	}
 
-	while (!strcmp(findbuf.cFileName, ".") ||
-			!strcmp(findbuf.cFileName, ".."))
-		if (!FindNextFile(handle, &findbuf)) {
-			strbuf_release(&buf);
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf))
 			return GetLastError() == ERROR_NO_MORE_FILES;
-		}
 	FindClose(handle);
-	strbuf_release(&buf);
 	return 0;
 }
 
-#undef rmdir
 int mingw_rmdir(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
-	while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
-		if (!is_dir_empty(pathname)) {
+		if (!is_dir_empty(wpathname)) {
 			errno = ENOTEMPTY;
 			break;
 		}
@@ -276,14 +276,14 @@ int mingw_rmdir(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = rmdir(pathname);
+	       ret = _wrmdir(wpathname);
 	return ret;
 }
 
-static int make_hidden(const char *path)
+static int make_hidden(const wchar_t *path)
 {
-	DWORD attribs = GetFileAttributes(path);
-	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+	DWORD attribs = GetFileAttributesW(path);
+	if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
 		return 0;
 	errno = err_win_to_posix(GetLastError());
 	return -1;
@@ -291,19 +291,23 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
-	    make_hidden(dir))
-		warning("Failed to make '%s' hidden", dir);
+	wchar_t wdir[MAX_PATH];
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
+		if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
+			warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
 		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
 		 "dotGitOnly" : "true"));
 }
 
-#undef mkdir
 int mingw_mkdir(const char *path, int mode)
 {
-	int ret = mkdir(path);
+	int ret;
+	wchar_t wpath[MAX_PATH];
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
 	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
 		/*
 		 * In Windows a file or dir starting with a dot is not
@@ -312,17 +316,17 @@ int mingw_mkdir(const char *path, int mode)
 		 */
 		const char *start = basename((char*)path);
 		if (*start == '.')
-			return make_hidden(path);
+			return make_hidden(wpath);
 	}
 	return ret;
 }
 
-#undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
 	va_list args;
 	unsigned mode;
 	int fd;
+	wchar_t wfilename[MAX_PATH];
 
 	va_start(args, oflags);
 	mode = va_arg(args, int);
@@ -331,10 +335,12 @@ int mingw_open (const char *filename, int oflags, ...)
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
 
-	fd = open(filename, oflags, mode);
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	fd = _wopen(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
-		DWORD attrs = GetFileAttributes(filename);
+		DWORD attrs = GetFileAttributesW(wfilename);
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
@@ -346,7 +352,7 @@ int mingw_open (const char *filename, int oflags, ...)
 		 * such a file is created.
 		 */
 		const char *start = basename((char*)filename);
-		if (*start == '.' && make_hidden(filename))
+		if (*start == '.' && make_hidden(wfilename))
 			warning("Could not mark '%s' as hidden.", filename);
 	}
 	return fd;
@@ -369,38 +375,69 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 	return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
-#undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = fopen(filename, otype);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfopen(wfilename, wotype);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
-#undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = freopen(filename, otype, stream);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -426,10 +463,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
  */
 static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
-	int err;
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
-	if (!(err = get_file_attr(file_name, &fdata))) {
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
 		buf->st_ino = 0;
 		buf->st_gid = 0;
 		buf->st_uid = 0;
@@ -442,8 +481,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-			WIN32_FIND_DATAA findbuf;
-			HANDLE handle = FindFirstFileA(file_name, &findbuf);
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
 			if (handle != INVALID_HANDLE_VALUE) {
 				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
 						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
@@ -462,7 +501,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		}
 		return 0;
 	}
-	errno = err;
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	default:
+		errno = ENOENT;
+		break;
+	}
 	return -1;
 }
 
@@ -551,16 +606,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
 {
 	FILETIME mft, aft;
 	int fh, rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
 	/* must have write permission */
-	DWORD attrs = GetFileAttributes(file_name);
+	attrs = GetFileAttributesW(wfilename);
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors here; open() will report them */
-		SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
 	}
 
-	if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+	if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
 		rc = -1;
 		goto revert_attrs;
 	}
@@ -583,7 +642,7 @@ revert_attrs:
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors again */
-		SetFileAttributes(file_name, attrs);
+		SetFileAttributesW(wfilename, attrs);
 	}
 	return rc;
 }
@@ -594,6 +653,18 @@ unsigned int sleep (unsigned int seconds)
 	return 0;
 }
 
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
 int mkstemp(char *template)
 {
 	char *filename = mktemp(template);
@@ -652,17 +723,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
 	return result;
 }
 
-#undef getcwd
 char *mingw_getcwd(char *pointer, int len)
 {
 	int i;
-	char *ret = getcwd(pointer, len);
-	if (!ret)
-		return ret;
+	wchar_t wpointer[MAX_PATH];
+	if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+		return NULL;
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
 	for (i = 0; pointer[i]; i++)
 		if (pointer[i] == '\\')
 			pointer[i] = '/';
-	return ret;
+	return pointer;
 }
 
 #undef getenv
@@ -1495,33 +1567,36 @@ int mingw_rename(const char *pold, const char *pnew)
 {
 	DWORD attrs, gle;
 	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+		return -1;
 
 	/*
 	 * Try native rename() first to get errno right.
 	 * It is based on MoveFile(), which cannot overwrite existing files.
 	 */
-	if (!rename(pold, pnew))
+	if (!_wrename(wpold, wpnew))
 		return 0;
 	if (errno != EEXIST)
 		return -1;
 repeat:
-	if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 		return 0;
 	/* TODO: translate more errors */
 	gle = GetLastError();
 	if (gle == ERROR_ACCESS_DENIED &&
-	    (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
 		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
 			errno = EISDIR;
 			return -1;
 		}
 		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
-		    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
-			if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 				return 0;
 			gle = GetLastError();
 			/* revert file attributes on failure */
-			SetFileAttributes(pnew, attrs);
+			SetFileAttributesW(wpnew, attrs);
 		}
 	}
 	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
@@ -1731,11 +1806,16 @@ void mingw_open_html(const char *unixpath)
 
 int link(const char *oldpath, const char *newpath)
 {
-	typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+	typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
 	static T create_hard_link = NULL;
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
 	if (!create_hard_link) {
 		create_hard_link = (T) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+			GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
 		if (!create_hard_link)
 			create_hard_link = (T)-1;
 	}
@@ -1743,7 +1823,7 @@ int link(const char *oldpath, const char *newpath)
 		errno = ENOSYS;
 		return -1;
 	}
-	if (!create_hard_link(newpath, oldpath, NULL)) {
+	if (!create_hard_link(wnewpath, woldpath, NULL)) {
 		errno = err_win_to_posix(GetLastError());
 		return -1;
 	}
diff --git a/compat/mingw.h b/compat/mingw.h
index ddb228473b..ea8c1f8993 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -182,6 +182,19 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 

From e40b9979f74e81d55a11886ecbc7c20d2614fcef Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:01:09 +0100
Subject: [PATCH 3201/3720] Win32: Unicode file name support (dirent)

Changes opendir/readdir to use Windows Unicode APIs and convert between
UTF-8/UTF-16.

Removes parameter checks that are already covered by xutftowcs_path. This
changes detection of ENAMETOOLONG from MAX_PATH - 2 to MAX_PATH (matching
is_dir_empty in mingw.c). If name + "/*" or the resulting absolute path is
too long, FindFirstFile fails and errno is set through err_win_to_posix.

Increases the size of dirent.d_name to accommodate the full
WIN32_FIND_DATA.cFileName converted to UTF-8 (UTF-16 to UTF-8 conversion
may grow by factor three in the worst case).

Signed-off-by: Karsten Blees 
---
 compat/win32/dirent.c | 30 ++++++++++--------------------
 compat/win32/dirent.h |  2 +-
 2 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 82a515c21b..52420ec7d4 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -6,10 +6,10 @@ struct DIR {
 	int dd_stat;          /* 0-based index */
 };
 
-static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
 {
-	/* copy file name from WIN32_FIND_DATA to dirent */
-	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+	/* convert UTF-16 name to UTF-8 */
+	xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
 
 	/* Set file type, based on WIN32_FIND_DATA */
 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -20,25 +20,15 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
 
 DIR *opendir(const char *name)
 {
-	char pattern[MAX_PATH];
-	WIN32_FIND_DATAA fdata;
+	wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
+	WIN32_FIND_DATAW fdata;
 	HANDLE h;
 	int len;
 	DIR *dir;
 
-	/* check that name is not NULL */
-	if (!name) {
-		errno = EINVAL;
+	/* convert name to UTF-16 and check length < MAX_PATH */
+	if ((len = xutftowcs_path(pattern, name)) < 0)
 		return NULL;
-	}
-	/* check that the pattern won't be too long for FindFirstFileA */
-	len = strlen(name);
-	if (len + 2 >= MAX_PATH) {
-		errno = ENAMETOOLONG;
-		return NULL;
-	}
-	/* copy name to temp buffer */
-	memcpy(pattern, name, len + 1);
 
 	/* append optional '/' and wildcard '*' */
 	if (len && !is_dir_sep(pattern[len - 1]))
@@ -47,7 +37,7 @@ DIR *opendir(const char *name)
 	pattern[len] = 0;
 
 	/* open find handle */
-	h = FindFirstFileA(pattern, &fdata);
+	h = FindFirstFileW(pattern, &fdata);
 	if (h == INVALID_HANDLE_VALUE) {
 		DWORD err = GetLastError();
 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
@@ -72,8 +62,8 @@ struct dirent *readdir(DIR *dir)
 	/* if first entry, dirent has already been set up by opendir */
 	if (dir->dd_stat) {
 		/* get next entry and convert from WIN32_FIND_DATA to dirent */
-		WIN32_FIND_DATAA fdata;
-		if (FindNextFileA(dir->dd_handle, &fdata)) {
+		WIN32_FIND_DATAW fdata;
+		if (FindNextFileW(dir->dd_handle, &fdata)) {
 			finddata2dirent(&dir->dd_dir, &fdata);
 		} else {
 			DWORD lasterr = GetLastError();
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 8838cd61fc..058207e4bf 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,7 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
-	char d_name[MAX_PATH];     /* file name */
+	char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
 };
 
 DIR *opendir(const char *dirname);

From 16de78633c4caf0a9715e51dfe35c4cb8338714e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 4 Feb 2012 21:54:36 +0100
Subject: [PATCH 3202/3720] Unicode file name support (gitk and git-gui)

Assumes file names in git tree objects are UTF-8 encoded.

On most unix systems, the system encoding (and thus the TCL system
encoding) will be UTF-8, so file names will be displayed correctly.

On Windows, it is impossible to set the system encoding to UTF-8. Changing
the TCL system encoding (via 'encoding system ...', e.g. in the startup
code) is explicitly discouraged by the TCL docs.

Change gitk and git-gui functions dealing with file names to always convert
from and to UTF-8.

Signed-off-by: Karsten Blees 
---
 git-gui/git-gui.sh      | 11 +++++++----
 git-gui/lib/browser.tcl |  2 +-
 git-gui/lib/index.tcl   |  6 +++---
 gitk-git/gitk           | 16 ++++++++--------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index a59020bcc5..e5038ddd12 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -533,6 +533,9 @@ proc git {args} {
 
 	_trace_exec [concat $opt $cmdp $args]
 	set result [eval exec $opt $cmdp $args]
+	if {[encoding system] != "utf-8"} {
+		set result [encoding convertfrom utf-8 [encoding convertto $result]]
+	}
 	if {$::_trace} {
 		puts stderr "< $result"
 	}
@@ -1087,7 +1090,7 @@ git-version proc _parse_config {arr_name args} {
 				[list git_read config] \
 				$args \
 				[list --null --list]]
-			fconfigure $fd_rc -translation binary
+			fconfigure $fd_rc -translation binary -encoding utf-8
 			set buf [read $fd_rc]
 			close $fd_rc
 		}
@@ -1652,7 +1655,7 @@ proc read_diff_index {fd after} {
 		set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			[lindex $i 4]? \
 			[list [lindex $i 0] [lindex $i 2]] \
 			[list]
@@ -1685,7 +1688,7 @@ proc read_diff_files {fd after} {
 		set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			?[lindex $i 4] \
 			[list] \
 			[list [lindex $i 0] [lindex $i 2]]
@@ -1708,7 +1711,7 @@ proc read_ls_others {fd after} {
 	set pck [split $buf_rlo "\0"]
 	set buf_rlo [lindex $pck end]
 	foreach p [lrange $pck 0 end-1] {
-		set p [encoding convertfrom $p]
+		set p [encoding convertfrom utf-8 $p]
 		if {[string index $p end] eq {/}} {
 			set p [string range $p 0 end-1]
 		}
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 4fca8fb13c..555db896f4 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary
+	fconfigure $fd -blocking 0 -translation binary -encoding utf-8
 	fileevent $fd readable [cb _read $fd]
 }
 
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdde21..6ca0a6e369 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -115,7 +115,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
 		set info [lindex $s 2]
 		if {$info eq {}} continue
 
-		puts -nonewline $fd "$info\t[encoding convertto $path]\0"
+		puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -186,7 +186,7 @@ proc write_update_index {fd pathList totalCnt batch after} {
 		?M {set new M_}
 		?? {continue}
 		}
-		puts -nonewline $fd "[encoding convertto $path]\0"
+		puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -247,7 +247,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
 		?M -
 		?T -
 		?D {
-			puts -nonewline $fd "[encoding convertto $path]\0"
+			puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 			display_file $path ?_
 		}
 		}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 3660096db5..f9e936d69e 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7288,7 +7288,7 @@ proc gettreeline {gtf id} {
 	if {[string index $fname 0] eq "\""} {
 	    set fname [lindex $fname 0]
 	}
-	set fname [encoding convertfrom $fname]
+	set fname [encoding convertfrom utf-8 $fname]
 	lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -7507,7 +7507,7 @@ proc gettreediffline {gdtf ids} {
 	    if {[string index $file 0] eq "\""} {
 		set file [lindex $file 0]
 	    }
-	    set file [encoding convertfrom $file]
+	    set file [encoding convertfrom utf-8 $file]
 	    if {$file ne [lindex $treediff end]} {
 		lappend treediff $file
 		lappend sublist $file
@@ -7656,7 +7656,7 @@ proc makediffhdr {fname ids} {
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -7690,7 +7690,7 @@ proc getblobdiffline {bdf ids} {
 	}
 	if {![string compare -length 5 "diff " $line]} {
 	    if {![regexp {^diff (--cc|--git) } $line m type]} {
-		set line [encoding convertfrom $line]
+		set line [encoding convertfrom utf-8 $line]
 		$ctext insert end "$line\n" hunksep
 		continue
 	    }
@@ -7737,7 +7737,7 @@ proc getblobdiffline {bdf ids} {
 	    makediffhdr $fname $ids
 
 	} elseif {![string compare -length 16 "* Unmerged path " $line]} {
-	    set fname [encoding convertfrom [string range $line 16 end]]
+	    set fname [encoding convertfrom utf-8 [string range $line 16 end]]
 	    $ctext insert end "\n"
 	    set curdiffstart [$ctext index "end - 1c"]
 	    lappend ctext_file_names $fname
@@ -7792,7 +7792,7 @@ proc getblobdiffline {bdf ids} {
 		if {[string index $fname 0] eq "\""} {
 		    set fname [lindex $fname 0]
 		}
-		set fname [encoding convertfrom $fname]
+		set fname [encoding convertfrom utf-8 $fname]
 		set i [lsearch -exact $treediffs($ids) $fname]
 		if {$i >= 0} {
 		    setinlist difffilestart $i $curdiffstart
@@ -7811,7 +7811,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
-	    set line [encoding convertfrom $line]
+	    set line [encoding convertfrom utf-8 $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {
@@ -11460,7 +11460,7 @@ proc cache_gitattr {attr pathlist} {
 	    foreach row [split $rlist "\n"] {
 		if {[regexp "(.*): $attr: (.*)" $row m path value]} {
 		    if {[string index $path 0] eq "\""} {
-			set path [encoding convertfrom [lindex $path 0]]
+			set path [encoding convertfrom utf-8 [lindex $path 0]]
 		    }
 		    set path_attr_cache($attr,$path) $value
 		}

From 0a8d0ef92fef311ce641eb671b4dd5d875475c17 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:27:53 +0100
Subject: [PATCH 3203/3720] Win32: Unicode arguments (outgoing)

Convert command line arguments from UTF-8 to UTF-16 when creating other
processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 5d5f30bd2c..de0a55fe84 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -955,9 +955,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFO si;
+	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
 	struct strbuf envblk, args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
 	unsigned flags;
 	BOOL ret;
 
@@ -993,6 +994,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	si.hStdOutput = winansi_get_osfhandle(fhout);
 	si.hStdError = winansi_get_osfhandle(fherr);
 
+	if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
 	if (prepend_cmd) {
@@ -1010,6 +1016,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			free(quoted);
 	}
 
+	wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
@@ -1031,12 +1041,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	}
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir, &si, &pi);
+	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
 	if (env)
 		strbuf_release(&envblk);
-	strbuf_release(&args);
+	free(wargs);
 
 	if (!ret) {
 		errno = ENOENT;

From 6fc4e029c190793fe02bad9ac0fa6c39bf951d98 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:28:27 +0100
Subject: [PATCH 3204/3720] Win32: Unicode arguments (incoming)

Convert command line arguments from UTF-16 to UTF-8 on startup.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index de0a55fe84..428c056009 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2040,10 +2040,41 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
  */
 int _CRT_glob = 0;
 
+typedef struct {
+	int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+		_startupinfo *si);
+
 void mingw_startup()
 {
-	/* copy executable name to argv[0] */
-	__argv[0] = xstrdup(_pgmptr);
+	int i, len, maxlen, argc;
+	char *buffer;
+	wchar_t **wenv, **wargv;
+	_startupinfo si;
+
+	/* get wide char arguments and environment */
+	si.newmode = 0;
+	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(_wpgmptr);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = xmalloc(maxlen);
+
+	/* convert command line arguments and environment to UTF-8 */
+	len = xwcstoutf(buffer, _wpgmptr, maxlen);
+	__argv[0] = xmemdupz(buffer, len);
+	for (i = 1; i < argc; i++) {
+		len = xwcstoutf(buffer, wargv[i], maxlen);
+		__argv[i] = xmemdupz(buffer, len);
+	}
+	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);

From 15a32e82bd6e88360fe6f3d1750888f96918735d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:17:49 +0100
Subject: [PATCH 3205/3720] Win32: sync Unicode console output and file system

Use the same Unicode conversion functions for file names and console
conversions so that the file system and console output are in sync when
checking out legacy encoded repositories (i.e. with invalid UTF-8 file
names).

Signed-off-by: Karsten Blees 
---
 compat/winansi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a3e4d88295..9f95954390 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -120,8 +120,7 @@ static void write_console(unsigned char *str, size_t len)
 	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
 
 	/* convert utf-8 to utf-16 */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
-			ARRAY_SIZE(wbuf));
+	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);

From 26b0dac662a34ce4bfae3f8d6eb882d0ae1c866c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:07:46 +0100
Subject: [PATCH 3206/3720] Win32: Unicode environment (outgoing)

Convert environment from UTF-8 to UTF-16 when creating other processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 428c056009..d78ac239e0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -957,9 +957,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 {
 	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
-	struct strbuf envblk, args;
-	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
-	unsigned flags;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 
 	/* Determine whether or not we are associated to a console */
@@ -976,7 +976,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * instead of CREATE_NO_WINDOW to make ssh
 		 * recognize that it has no console.
 		 */
-		flags = DETACHED_PROCESS;
+		flags |= DETACHED_PROCESS;
 	} else {
 		/* There is already a console. If we specified
 		 * DETACHED_PROCESS here, too, Windows would
@@ -984,7 +984,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * The same is true for CREATE_NO_WINDOW.
 		 * Go figure!
 		 */
-		flags = 0;
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
@@ -1023,6 +1022,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
+		int size = 0, wenvsz = 0, wenvpos = 0;
 
 		for (e = env; *e; e++)
 			count++;
@@ -1032,20 +1032,22 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
 		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
 
-		strbuf_init(&envblk, 0);
+		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
-			strbuf_addstr(&envblk, *e);
-			strbuf_addch(&envblk, '\0');
+			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
 		}
+		/* add final \0 terminator */
+		wenvblk[wenvpos] = 0;
 		free(sorted_env);
 	}
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
+		wenvblk, dir ? wdir : NULL, &si, &pi);
 
-	if (env)
-		strbuf_release(&envblk);
+	free(wenvblk);
 	free(wargs);
 
 	if (!ret) {

From 826493a6f55bd491c05ebf17ad76f9241d134ee3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 25 Apr 2011 23:32:27 +0100
Subject: [PATCH 3207/3720] Win32: Unicode environment (incoming)

Convert environment from UTF-16 to UTF-8 on startup.

No changes to getenv() are necessary, as the MSVCRT version is implemented
on top of char **environ.

However, putenv / _wputenv from MSVCRT no longer work, for two reasons:
1. they try to keep environ, _wenviron and the Win32 process environment
in sync, using the default system encoding instead of UTF-8 to convert
between charsets
2. msysgit and MSVCRT use different allocators, memory allocated in git
cannot be freed by the CRT and vice versa

Implement mingw_putenv using the env_setenv helper function from the
environment merge code.

Note that in case of memory allocation failure, putenv now dies with error
message (due to xrealloc) instead of failing with ENOMEM. As git assumes
setenv / putenv to always succeed, this prevents it from continuing with
incorrect settings.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index d78ac239e0..fe1d0de81f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1282,6 +1282,12 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -2064,6 +2070,11 @@ void mingw_startup()
 	maxlen = wcslen(_wpgmptr);
 	for (i = 1; i < argc; i++)
 		maxlen = max(maxlen, wcslen(wargv[i]));
+	for (i = 0; wenv[i]; i++)
+		maxlen = max(maxlen, wcslen(wenv[i]));
+
+	/* nedmalloc can't free CRT memory, allocate resizable environment list */
+	environ = xcalloc(i + 1, sizeof(char*));
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2076,6 +2087,10 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wargv[i], maxlen);
 		__argv[i] = xmemdupz(buffer, len);
 	}
+	for (i = 0; wenv[i]; i++) {
+		len = xwcstoutf(buffer, wenv[i], maxlen);
+		environ[i] = xmemdupz(buffer, len);
+	}
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
diff --git a/compat/mingw.h b/compat/mingw.h
index ea8c1f8993..af1574c435 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -200,6 +200,8 @@ char *mingw_getcwd(char *pointer, int len);
 
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
+int mingw_putenv(const char *namevalue);
+#define putenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 0399e42bf328314a9db2934134a67710d1a08a38 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 20 Aug 2011 14:27:02 +0200
Subject: [PATCH 3208/3720] MinGW: disable legacy encoding tests

On Windows, all native APIs are Unicode-based. It is impossible to pass
legacy encoded byte arrays to a process via command line or environment
variables. Disable the tests that try to do so.

In t3901, most tests still work if we don't mess up the repository encoding
in setup, so don't switch to ISO-8859-1 on MinGW.

Note that i18n tests that do their encoding tricks via encoded files (such
as t3900) are not affected by this.

Signed-off-by: Karsten Blees 
---
 t/t3901-i18n-patch.sh | 19 +++++++++++--------
 t/t4201-shortlog.sh   |  6 +++---
 t/t8005-blame-i18n.sh |  8 ++++----
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 31a5770b34..55c8a2f576 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -54,10 +54,13 @@ test_expect_success setup '
 	git add yours &&
 	git commit -s -m "Second on side" &&
 
-	# the second one on the side branch is ISO-8859-1
-	git config i18n.commitencoding ISO8859-1 &&
-	# use author and committer name in ISO-8859-1 to match it.
-	. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+	if test_have_prereq NOT_MINGW
+	then
+		# the second one on the side branch is ISO-8859-1
+		git config i18n.commitencoding ISO8859-1 &&
+		# use author and committer name in ISO-8859-1 to match it.
+		. "$TEST_DIRECTORY"/t3901-8859-1.txt
+	fi &&
 	test_tick &&
 	echo Yet another >theirs &&
 	git add theirs &&
@@ -119,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
 	check_encoding 2
 '
 
-test_expect_success 'rebase (L/L)' '
+test_expect_success NOT_MINGW 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
 	git config i18n.commitencoding ISO8859-1 &&
 	git config i18n.logoutputencoding ISO8859-1 &&
@@ -131,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 	check_encoding 2 8859
 '
 
-test_expect_success 'rebase (L/U)' '
+test_expect_success NOT_MINGW 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
 	git config i18n.commitencoding ISO8859-1 &&
@@ -159,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/L)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
 	git config i18n.commitencoding ISO8859-1 &&
@@ -189,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/U)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6872ba1a42..48963811bf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
 	test_cmp expect log.predictable
 '
 
-test_expect_success 'shortlog wrapping' '
+test_expect_success NOT_MINGW 'shortlog wrapping' '
 	cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
 	test_cmp expect out
 '
 
-test_expect_success 'shortlog from non-git directory' '
+test_expect_success NOT_MINGW 'shortlog from non-git directory' '
 	git log HEAD >log &&
 	GIT_DIR=non-existing git shortlog -w out &&
 	test_cmp expect out
@@ -135,7 +135,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success 'shortlog encoding' '
+test_expect_success NOT_MINGW 'shortlog encoding' '
 	git reset --hard "$commit" &&
 	git config --unset i18n.commitencoding &&
 	echo 2 > a1 &&
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index cb390559f9..a6e73d0635 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.commitencoding' '
 	git blame --incremental file | \
 		egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.logoutputencoding' '
 	git config i18n.logoutputencoding eucJP &&
 	git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=UTF-8' '
 	git blame --incremental --encoding=UTF-8 file | \
 		egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=none' '
 	git blame --incremental --encoding=none file | \
 		egrep "^(author|summary) " > actual &&

From 9c0fe9af086b6189c4e17722341b9fefc6c47021 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:29:40 +0100
Subject: [PATCH 3209/3720] Win32: fix environment memory leaks

All functions that modify the environment have memory leaks.

Disable gitunsetenv in the Makefile and use env_setenv (via mingw_putenv)
instead (this frees removed environment entries).

Move xstrdup from env_setenv to make_augmented_environ, so that
mingw_putenv no longer copies the environment entries (according to POSIX
[1], "the string [...] shall become part of the environment"). This also
fixes the memory leak in gitsetenv, which expects a POSIX compliant putenv.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html

Note: This patch depends on taking control of char **environ and having
our own mingw_putenv (both introduced in "Win32: Unicode environment
(incoming)").

Signed-off-by: Karsten Blees 
---
 Makefile       |  2 --
 compat/mingw.c | 10 ++++++----
 compat/mingw.h |  1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index c82f297f0f..77111b1f46 100644
--- a/Makefile
+++ b/Makefile
@@ -1160,7 +1160,6 @@ ifeq ($(uname_S),Windows)
 	NO_IPV6 = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
@@ -1257,7 +1256,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SYMLINK_HEAD = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index fe1d0de81f..bbd35d8bd4 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1255,14 +1255,14 @@ static char **env_setenv(char **env, const char *name)
 			for (i = 0; env[i]; i++)
 				;
 			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 			env[i+1] = NULL;
 		}
 	}
 	else {
 		free(env[i]);
 		if (*eq)
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 		else
 			for (; env[i]; i++)
 				env[i] = env[i+1];
@@ -1277,8 +1277,10 @@ char **make_augmented_environ(const char *const *vars)
 {
 	char **env = copy_environ();
 
-	while (*vars)
-		env = env_setenv(env, *vars++);
+	while (*vars) {
+		const char *v = *vars++;
+		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+	}
 	return env;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index af1574c435..ba21474515 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -202,6 +202,7 @@ char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 int mingw_putenv(const char *namevalue);
 #define putenv mingw_putenv
+#define unsetenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 717a8bb14d4268f699d66d162d16bd02696122e8 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 23:42:09 +0100
Subject: [PATCH 3210/3720] Win32: unify environment case-sensitivity

The environment on Windows is case-insensitive. Some environment functions
(such as unsetenv and make_augmented_environ) have always used case-
sensitive comparisons instead, while others (getenv, putenv, sorting in
spawn*) were case-insensitive.

Prevent potential inconsistencies by using case-insensitive comparison in
lookup_env (used by putenv, unsetenv and make_augmented_environ).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bbd35d8bd4..bef2f3314e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1234,8 +1234,7 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 	int i;
 
 	for (i = 0; env[i]; i++) {
-		if (0 == strncmp(env[i], name, nmln)
-		    && '=' == env[i][nmln])
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
 			/* matches */
 			return i;
 	}

From ea6b55cad4e2f6f9a871e9f8954d81eb2f927767 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:33:17 +0100
Subject: [PATCH 3211/3720] Win32: simplify internal mingw_spawn* APIs

The only public spawn function that needs to tweak the environment is
mingw_spawnvpe (called from start_command). Nevertheless, all internal
spawn* functions take an env parameter and needlessly pass the global
char **environ around. Remove the env parameter where it's not needed.

This removes the internal mingw_execve abstraction, which is no longer
needed.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bef2f3314e..311a1832d0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1077,10 +1077,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-			   int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -1122,7 +1121,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 	return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
 	const char *interpr = parse_interpreter(cmd);
 	char **path;
@@ -1140,7 +1139,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 		argv2 = xmalloc(sizeof(*argv) * (argc+1));
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-		pid = mingw_spawnve(prog, argv2, env, 1);
+		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -1155,13 +1154,13 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 	return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+void mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
-	if (!try_shell_exec(cmd, argv, (char **)env)) {
+	if (!try_shell_exec(cmd, argv)) {
 		int pid, status;
 
-		pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
 			return;
 		if (waitpid(pid, &status, 0) < 0)
@@ -1176,7 +1175,7 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	char *prog = path_lookup(cmd, path, 0);
 
 	if (prog) {
-		mingw_execve(prog, argv, environ);
+		mingw_execv(prog, argv);
 		free(prog);
 	} else
 		errno = ENOENT;
@@ -1184,11 +1183,6 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	free_path_split(path);
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
-{
-	mingw_execve(cmd, argv, environ);
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
 	if (pid > 0 && sig == SIGTERM) {

From e6a2065ea0a8cf8a1890f64bd7ada2bd9af0da4c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:05:04 +0100
Subject: [PATCH 3212/3720] Win32: move environment functions

Move environment helper functions up so that they can be reused by
mingw_getenv and mingw_spawnve_fd in subsequent patches.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 106 ++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 311a1832d0..0c406669df 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,6 +737,53 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
+static int env_compare(const void *a, const void *b)
+{
+	char *const *ea = a;
+	char *const *eb = b;
+	return strcasecmp(*ea, *eb);
+}
+
+static int lookup_env(char **env, const char *name, size_t nmln)
+{
+	int i;
+
+	for (i = 0; env[i]; i++) {
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
+			/* matches */
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * If name contains '=', then sets the variable, otherwise it unsets it
+ */
+static char **env_setenv(char **env, const char *name)
+{
+	char *eq = strchrnul(name, '=');
+	int i = lookup_env(env, name, eq-name);
+
+	if (i < 0) {
+		if (*eq) {
+			for (i = 0; env[i]; i++)
+				;
+			env = xrealloc(env, (i+2)*sizeof(*env));
+			env[i] = (char*) name;
+			env[i+1] = NULL;
+		}
+	}
+	else {
+		free(env[i]);
+		if (*eq)
+			env[i] = (char*) name;
+		else
+			for (; env[i]; i++)
+				env[i] = env[i+1];
+	}
+	return env;
+}
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -754,6 +801,12 @@ char *mingw_getenv(const char *name)
 	return result;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -936,13 +989,6 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
-static int env_compare(const void *a, const void *b)
-{
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
-}
-
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1223,46 +1269,6 @@ void free_environ(char **env)
 	free(env);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
-{
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
-	}
-	return -1;
-}
-
-/*
- * If name contains '=', then sets the variable, otherwise it unsets it
- */
-static char **env_setenv(char **env, const char *name)
-{
-	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
-
-	if (i < 0) {
-		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
-		}
-	}
-	else {
-		free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-	}
-	return env;
-}
-
 /*
  * Copies global environ and adjusts variables as specified by vars.
  */
@@ -1277,12 +1283,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-int mingw_putenv(const char *namevalue)
-{
-	environ = env_setenv(environ, namevalue);
-	return 0;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 4056e657e2ae9e08bffaa7b24c52421f0729a882 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Wed, 5 Oct 2011 22:01:46 +0200
Subject: [PATCH 3213/3720] Win32: unify environment function names

Environment helper functions use random naming ('env' prefix or suffix or
both, with or without '_'). Change to POSIX naming scheme ('env' suffix,
no '_').

Env_setenv has more in common with putenv than setenv. Change to do_putenv.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0c406669df..e5d8c6a438 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,14 +737,14 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int env_compare(const void *a, const void *b)
+static int compareenv(const void *a, const void *b)
 {
 	char *const *ea = a;
 	char *const *eb = b;
 	return strcasecmp(*ea, *eb);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
+static int lookupenv(char **env, const char *name, size_t nmln)
 {
 	int i;
 
@@ -759,10 +759,10 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **env_setenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name)
 {
 	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
+	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
@@ -803,7 +803,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = env_setenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue);
 	return 0;
 }
 
@@ -1076,7 +1076,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		/* environment must be sorted */
 		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
 
 		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
@@ -1278,7 +1278,7 @@ char **make_augmented_environ(const char *const *vars)
 
 	while (*vars) {
 		const char *v = *vars++;
-		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
 	}
 	return env;
 }

From 3229b66a4402b883ed1f5e1e6abbf7f86445a1e8 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:31:57 +0100
Subject: [PATCH 3214/3720] Win32: factor out environment block creation

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 55 +++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e5d8c6a438..be381573f1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -989,6 +989,36 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
+/*
+ * Create environment block suitable for CreateProcess.
+ */
+static wchar_t *make_environment_block(char **env)
+{
+	wchar_t *wenvblk = NULL;
+	int count = 0;
+	char **e, **tmpenv;
+	int size = 0, wenvsz = 0, wenvpos = 0;
+
+	for (e = env; *e; e++)
+		count++;
+
+	/* environment must be sorted */
+	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+
+	/* create environment block from temporary environment */
+	for (e = tmpenv; *e; e++) {
+		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+	}
+	/* add final \0 terminator */
+	wenvblk[wenvpos] = 0;
+	free(tmpenv);
+	return wenvblk;
+}
+
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1065,29 +1095,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env) {
-		int count = 0;
-		char **e, **sorted_env;
-		int size = 0, wenvsz = 0, wenvpos = 0;
-
-		for (e = env; *e; e++)
-			count++;
-
-		/* environment must be sorted */
-		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
-		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
-
-		/* create environment block from temporary environment */
-		for (e = sorted_env; *e; e++) {
-			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
-			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
-		}
-		/* add final \0 terminator */
-		wenvblk[wenvpos] = 0;
-		free(sorted_env);
-	}
+	if (env)
+		wenvblk = make_environment_block(env);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,

From 9286ef390f8211d6a3e500117a58c358d843a324 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:57:14 +0100
Subject: [PATCH 3215/3720] Win32: don't copy the environment twice when
 spawning child processes

When spawning child processes via start_command(), the environment and all
environment entries are copied twice. First by make_augmented_environ /
copy_environ to merge with child_process.env. Then a second time by
make_environment_block to create a sorted environment block string as
required by CreateProcess.

Move the merge logic to make_environment_block so that we only need to copy
the environment once. This changes semantics of the env parameter: it now
expects a delta (such as child_process.env) rather than a full environment.
This is not a problem as the parameter is only used by start_command()
(all other callers previously passed char **environ, and now pass NULL).

The merge logic no longer xstrdup()s the environment strings, so do_putenv
must not free them. Add a parameter to distinguish this from normal putenv.

Remove the now unused make_augmented_environ / free_environ API.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 74 ++++++++++++++++----------------------------------
 compat/mingw.h |  6 ----
 run-command.c  | 10 ++-----
 3 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index be381573f1..9a0b39a47e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -759,7 +759,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **do_putenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
@@ -774,7 +774,8 @@ static char **do_putenv(char **env, const char *name)
 		}
 	}
 	else {
-		free(env[i]);
+		if (free_old)
+			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
 		else
@@ -803,7 +804,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue, 1);
 	return 0;
 }
 
@@ -990,21 +991,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 }
 
 /*
- * Create environment block suitable for CreateProcess.
+ * Create environment block suitable for CreateProcess. Merges current
+ * process environment and the supplied environment changes.
  */
-static wchar_t *make_environment_block(char **env)
+static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
 	int count = 0;
 	char **e, **tmpenv;
 	int size = 0, wenvsz = 0, wenvpos = 0;
 
-	for (e = env; *e; e++)
+	while (environ[count])
 		count++;
 
-	/* environment must be sorted */
+	/* copy the environment */
 	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+
+	/* merge supplied environment changes into the temporary environment */
+	for (e = deltaenv; e && *e; e++)
+		tmpenv = do_putenv(tmpenv, *e, 0);
+
+	/* environment must be sorted */
+	for (count = 0; tmpenv[count]; )
+		count++;
 	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
 
 	/* create environment block from temporary environment */
@@ -1027,7 +1037,7 @@ struct pinfo_t {
 struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
-static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
@@ -1095,8 +1105,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env)
-		wenvblk = make_environment_block(env);
+	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1134,10 +1143,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
 static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 		     const char *dir,
 		     int fhin, int fhout, int fherr)
 {
@@ -1161,14 +1170,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 				pid = -1;
 			}
 			else {
-				pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
 						       fhin, fhout, fherr);
 				free(iprog);
 			}
 			argv[0] = argv0;
 		}
 		else
-			pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
 					       fhin, fhout, fherr);
 		free(prog);
 	}
@@ -1257,41 +1266,6 @@ int mingw_kill(pid_t pid, int sig)
 	return -1;
 }
 
-static char **copy_environ(void)
-{
-	char **env;
-	int i = 0;
-	while (environ[i])
-		i++;
-	env = xmalloc((i+1)*sizeof(*env));
-	for (i = 0; environ[i]; i++)
-		env[i] = xstrdup(environ[i]);
-	env[i] = NULL;
-	return env;
-}
-
-void free_environ(char **env)
-{
-	int i;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-/*
- * Copies global environ and adjusts variables as specified by vars.
- */
-char **make_augmented_environ(const char *const *vars)
-{
-	char **env = copy_environ();
-
-	while (*vars) {
-		const char *v = *vars++;
-		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
-	}
-	return env;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
diff --git a/compat/mingw.h b/compat/mingw.h
index ba21474515..04b6523255 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -335,12 +335,6 @@ void mingw_open_html(const char *path);
 void mingw_mark_as_git_dir(const char *dir);
 #define mark_as_git_dir mingw_mark_as_git_dir
 
-/*
- * helpers
- */
-
-char **make_augmented_environ(const char *const *vars);
-void free_environ(char **env);
 
 /**
  * Converts UTF-8 encoded string to UTF-16LE.
diff --git a/run-command.c b/run-command.c
index 1db8abf984..6d0dc3da91 100644
--- a/run-command.c
+++ b/run-command.c
@@ -381,7 +381,6 @@ fail_pipe:
 {
 	int fhin = 0, fhout = 1, fherr = 2;
 	const char **sargv = cmd->argv;
-	char **env = environ;
 
 	if (cmd->no_stdin)
 		fhin = open("/dev/null", O_RDWR);
@@ -406,25 +405,20 @@ fail_pipe:
 	else if (cmd->out > 1)
 		fhout = dup(cmd->out);
 
-	if (cmd->env)
-		env = make_augmented_environ(cmd->env);
-
 	if (cmd->git_cmd) {
 		cmd->argv = prepare_git_cmd(cmd->argv);
 	} else if (cmd->use_shell) {
 		cmd->argv = prepare_shell_cmd(cmd->argv);
 	}
 
-	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
-				  fhin, fhout, fherr);
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
 	failed_errno = errno;
 	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 		error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 	if (cmd->clean_on_exit && cmd->pid >= 0)
 		mark_child_for_cleanup(cmd->pid);
 
-	if (cmd->env)
-		free_environ(env);
 	if (cmd->git_cmd)
 		free(cmd->argv);
 

From baf5b1833af7dc3d2b273e6f7b986a8c2f9d1ecd Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:00:35 +0100
Subject: [PATCH 3216/3720] Win32: reduce environment array reallocations

Move environment array reallocation from do_putenv to the respective
callers. Keep track of the environment size in a global variable. Use
ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a
sufficiently sized environment array in make_environment_block to prevent
reallocations.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 60 ++++++++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9a0b39a47e..2d984bd8d3 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -758,19 +758,19 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
+ * Size includes the terminating NULL. Env must have room for size + 1 entries
+ * (in case of insert). Returns the new size. Optionally frees removed entries.
  */
-static char **do_putenv(char **env, const char *name, int free_old)
+static int do_putenv(char **env, const char *name, int size, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
+			env[size - 1] = (char*) name;
+			env[size] = NULL;
+			size++;
 		}
 	}
 	else {
@@ -778,13 +778,20 @@ static char **do_putenv(char **env, const char *name, int free_old)
 			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
-		else
+		else {
 			for (; env[i]; i++)
 				env[i] = env[i+1];
+			size--;
+		}
 	}
-	return env;
+	return size;
 }
 
+/* used number of elements of environ array, including terminating NULL */
+static int environ_size = 0;
+/* allocated size of environ array, in bytes */
+static int environ_alloc = 0;
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -804,7 +811,8 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue, 1);
+	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
+	environ_size = do_putenv(environ, namevalue, environ_size, 1);
 	return 0;
 }
 
@@ -997,31 +1005,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
-	int count = 0;
-	char **e, **tmpenv;
-	int size = 0, wenvsz = 0, wenvpos = 0;
+	char **tmpenv;
+	int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
 
-	while (environ[count])
-		count++;
+	while (deltaenv && deltaenv[i])
+		i++;
 
-	/* copy the environment */
-	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+	/* copy the environment, leaving space for changes */
+	tmpenv = xmalloc((size + i) * sizeof(char*));
+	memcpy(tmpenv, environ, size * sizeof(char*));
 
 	/* merge supplied environment changes into the temporary environment */
-	for (e = deltaenv; e && *e; e++)
-		tmpenv = do_putenv(tmpenv, *e, 0);
+	for (i = 0; deltaenv && deltaenv[i]; i++)
+		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
 	/* environment must be sorted */
-	for (count = 0; tmpenv[count]; )
-		count++;
-	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
 
 	/* create environment block from temporary environment */
-	for (e = tmpenv; *e; e++) {
-		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+	for (i = 0; tmpenv[i]; i++) {
+		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
 		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+		wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
 	}
 	/* add final \0 terminator */
 	wenvblk[wenvpos] = 0;
@@ -2052,7 +2057,9 @@ void mingw_startup()
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
 	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = xcalloc(i + 1, sizeof(char*));
+	environ = NULL;
+	environ_size = i + 1;
+	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2069,6 +2076,7 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wenv[i], maxlen);
 		environ[i] = xmemdupz(buffer, len);
 	}
+	environ[i] = NULL;
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */

From 54d3fa6f93c3933c117d9f51b2530d7f57b5c623 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:29:04 +0100
Subject: [PATCH 3217/3720] Win32: use low-level memory allocation during
 initialization

As of d41489a6 "Add more large blob test cases", git's high-level memory
allocation functions (xmalloc, xmemdupz etc.) access the environment to
simulate limited memory in tests (see 'getenv("GIT_ALLOC_LIMIT")' in
memory_limit_check()). These functions should not be used before the
environment is fully initialized (particularly not to initialize the
environment itself).

The current solution ('environ = NULL; ALLOC_GROW(environ...)') only works
because MSVCRT's getenv() reinitializes environ when it is NULL (i.e. it
leaves us with two sets of unusabe (non-UTF-8) and unfreeable (CRT-
allocated) environments).

Add our own set of malloc-or-die functions to be used in startup code.

Also check the result of __wgetmainargs, which may fail if there's not
enough memory for wide-char arguments and environment.

This patch is in preparation of the sorted environment feature, which
completely replaces MSVCRT's getenv() implementation.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 52 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2d984bd8d3..f6934f7b79 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2038,16 +2038,37 @@ typedef struct {
 extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
 		_startupinfo *si);
 
+static NORETURN void die_startup()
+{
+	fputs("fatal: not enough memory for initialization", stderr);
+	exit(128);
+}
+
+static void *malloc_startup(size_t size)
+{
+	void *result = malloc(size);
+	if (!result)
+		die_startup();
+	return result;
+}
+
+static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
+{
+	len = xwcstoutf(buffer, wcs, len) + 1;
+	return memcpy(malloc_startup(len), buffer, len);
+}
+
 void mingw_startup()
 {
-	int i, len, maxlen, argc;
+	int i, maxlen, argc;
 	char *buffer;
 	wchar_t **wenv, **wargv;
 	_startupinfo si;
 
 	/* get wide char arguments and environment */
 	si.newmode = 0;
-	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+	if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
+		die_startup();
 
 	/* determine size of argv and environ conversion buffer */
 	maxlen = wcslen(_wpgmptr);
@@ -2056,26 +2077,25 @@ void mingw_startup()
 	for (i = 0; wenv[i]; i++)
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
-	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = NULL;
+	/*
+	 * nedmalloc can't free CRT memory, allocate resizable environment
+	 * list. Note that xmalloc / xmemdupz etc. call getenv, so we cannot
+	 * use it while initializing the environment itself.
+	 */
 	environ_size = i + 1;
-	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
+	environ_alloc = alloc_nr(environ_size * sizeof(char*));
+	environ = malloc_startup(environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
-	buffer = xmalloc(maxlen);
+	buffer = malloc_startup(maxlen);
 
 	/* convert command line arguments and environment to UTF-8 */
-	len = xwcstoutf(buffer, _wpgmptr, maxlen);
-	__argv[0] = xmemdupz(buffer, len);
-	for (i = 1; i < argc; i++) {
-		len = xwcstoutf(buffer, wargv[i], maxlen);
-		__argv[i] = xmemdupz(buffer, len);
-	}
-	for (i = 0; wenv[i]; i++) {
-		len = xwcstoutf(buffer, wenv[i], maxlen);
-		environ[i] = xmemdupz(buffer, len);
-	}
+	__argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
+	for (i = 1; i < argc; i++)
+		__argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+	for (i = 0; wenv[i]; i++)
+		environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen);
 	environ[i] = NULL;
 	free(buffer);
 

From 3f371bb824fb964b88b55da45c18043eed0c7b87 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:30:02 +0100
Subject: [PATCH 3218/3720] Win32: keep the environment sorted

The Windows environment is sorted, keep it that way for O(log n)
environment access.

Change compareenv to compare only the keys, so that it can be used to
find an entry irrespective of the value.

Change lookupenv to binary seach for an entry. Return one's complement of
the insert position if not found (libc's bsearch returns NULL).

Replace MSVCRT's getenv with a minimal do_getenv based on the binary search
function.

Change do_putenv to insert new entries at the correct position. Simplify
the function by swapping if conditions and using memmove instead of for
loops.

Move qsort from make_environment_block to mingw_startup. We still need to
sort on startup to make sure that the environment is sorted according to
our compareenv function (while Win32 / CreateProcess requires the
environment block to be sorted case-insensitively, CreateProcess currently
doesn't enforce this, and some applications such as bash just don't care).

Note that environment functions are _not_ thread-safe and are not required
to be so by POSIX, the application is responsible for synchronizing access
to the environment. MSVCRT's getenv and our new getenv implementation are
better than that in that they are thread-safe with respect to other getenv
calls as long as the environment is not modified. Git's indiscriminate use
of getenv in background threads currently requires this property.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 98 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 62 insertions(+), 36 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f6934f7b79..67c9e9c4f6 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,23 +737,42 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int compareenv(const void *a, const void *b)
+/*
+ * Compare environment entries by key (i.e. stopping at '=' or '\0').
+ */
+static int compareenv(const void *v1, const void *v2)
 {
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
+	const char *e1 = *(const char**)v1;
+	const char *e2 = *(const char**)v2;
+
+	for (;;) {
+		int c1 = *e1++;
+		int c2 = *e2++;
+		c1 = (c1 == '=') ? 0 : tolower(c1);
+		c2 = (c2 == '=') ? 0 : tolower(c2);
+		if (c1 > c2)
+			return 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 == 0)
+			return 0;
+	}
 }
 
-static int lookupenv(char **env, const char *name, size_t nmln)
+static int bsearchenv(char **env, const char *name, size_t size)
 {
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
+	unsigned low = 0, high = size;
+	while (low < high) {
+		unsigned mid = low + ((high - low) >> 1);
+		int cmp = compareenv(&env[mid], &name);
+		if (cmp < 0)
+			low = mid + 1;
+		else if (cmp > 0)
+			high = mid;
+		else
+			return mid;
 	}
-	return -1;
+	return ~low; /* not found, return 1's complement of insert position */
 }
 
 /*
@@ -763,26 +782,24 @@ static int lookupenv(char **env, const char *name, size_t nmln)
  */
 static int do_putenv(char **env, const char *name, int size, int free_old)
 {
-	char *eq = strchrnul(name, '=');
-	int i = lookupenv(env, name, eq-name);
+	int i = bsearchenv(env, name, size - 1);
 
-	if (i < 0) {
-		if (*eq) {
-			env[size - 1] = (char*) name;
-			env[size] = NULL;
+	/* optionally free removed / replaced entry */
+	if (i >= 0 && free_old)
+		free(env[i]);
+
+	if (strchr(name, '=')) {
+		/* if new value ('key=value') is specified, insert or replace entry */
+		if (i < 0) {
+			i = ~i;
+			memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
 			size++;
 		}
-	}
-	else {
-		if (free_old)
-			free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else {
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-			size--;
-		}
+		env[i] = (char*) name;
+	} else if (i >= 0) {
+		/* otherwise ('key') remove existing entry */
+		size--;
+		memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
 	}
 	return size;
 }
@@ -792,15 +809,24 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-#undef getenv
+static char *do_getenv(const char *name)
+{
+	char *value;
+	int pos = bsearchenv(environ, name, environ_size - 1);
+	if (pos < 0)
+		return NULL;
+	value = strchr(environ[pos], '=');
+	return value ? &value[1] : NULL;
+}
+
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv(name);
+	char *result = do_getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
+		result = do_getenv("TMP");
 		if (!result)
-			result = getenv("TEMP");
+			result = do_getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */
@@ -1019,9 +1045,6 @@ static wchar_t *make_environment_block(char **deltaenv)
 	for (i = 0; deltaenv && deltaenv[i]; i++)
 		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
-	/* environment must be sorted */
-	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
-
 	/* create environment block from temporary environment */
 	for (i = 0; tmpenv[i]; i++) {
 		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
@@ -2099,6 +2122,9 @@ void mingw_startup()
 	environ[i] = NULL;
 	free(buffer);
 
+	/* sort environment for O(log n) getenv / putenv */
+	qsort(environ, i, sizeof(char*), compareenv);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From ea1074ae06a36d7a456bc0571b105ee37e4347c4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:35:26 +0100
Subject: [PATCH 3219/3720] Win32: patch Windows environment on startup

Fix Windows specific environment settings on startup rather than checking
for special values on every getenv call.

As a side effect, this makes the patched environment (i.e. with properly
initialized TMPDIR and TERM) available to child processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 67c9e9c4f6..36899908ee 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -809,7 +809,7 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-static char *do_getenv(const char *name)
+char *mingw_getenv(const char *name)
 {
 	char *value;
 	int pos = bsearchenv(environ, name, environ_size - 1);
@@ -819,22 +819,6 @@ static char *do_getenv(const char *name)
 	return value ? &value[1] : NULL;
 }
 
-char *mingw_getenv(const char *name)
-{
-	char *result = do_getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = do_getenv("TMP");
-		if (!result)
-			result = do_getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 int mingw_putenv(const char *namevalue)
 {
 	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
@@ -2125,6 +2109,21 @@ void mingw_startup()
 	/* sort environment for O(log n) getenv / putenv */
 	qsort(environ, i, sizeof(char*), compareenv);
 
+	/* fix Windows specific environment settings */
+
+	/* on Windows it is TMP and TEMP */
+	if (!getenv("TMPDIR")) {
+		const char *tmp = getenv("TMP");
+		if (!tmp)
+			tmp = getenv("TEMP");
+		if (tmp)
+			setenv("TMPDIR", tmp, 1);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "winansi", 1);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 838c34f81ce31752ad01898e6546f0c3a767dbaa Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:37:26 +0100
Subject: [PATCH 3220/3720] Win32: fix detection of empty directories in
 is_dir_empty

On Windows XP (not Win7), directories cannot be deleted while a find handle
is open, causing "Deletion of directory '...' failed. Should I try again?"
prompts.

Prior to 19d1e75d "Win32: Unicode file name support (except dirent)",
these failures were silently ignored due to strbuf_free in is_dir_empty
resetting GetLastError to ERROR_SUCCESS.

Close the find handle in is_dir_empty so that git doesn't block deletion
of the directory even after all other applications have released it.

Reported-by: John Chen 
Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 36899908ee..e6f331a581 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -243,8 +243,11 @@ static int is_dir_empty(const wchar_t *wpath)
 
 	while (!wcscmp(findbuf.cFileName, L".") ||
 			!wcscmp(findbuf.cFileName, L".."))
-		if (!FindNextFileW(handle, &findbuf))
-			return GetLastError() == ERROR_NO_MORE_FILES;
+		if (!FindNextFileW(handle, &findbuf)) {
+			DWORD err = GetLastError();
+			FindClose(handle);
+			return err == ERROR_NO_MORE_FILES;
+		}
 	FindClose(handle);
 	return 0;
 }

From 4e241d89207d5bc11658b291c3395d901a133aed Mon Sep 17 00:00:00 2001
From: Nelson Benitez Leon 
Date: Thu, 15 Mar 2012 10:52:02 +0100
Subject: [PATCH 3221/3720] http: try http_proxy env var when http.proxy config
 option is not set

cURL already reads it, but if $http_proxy has username but no password
cURL will not ask you for the password and so failed to authenticate
returning a 407 error code. So we read it ourselves to detect that and
ask for the password. Also we read it prior to connection to be able to
make a proactive authentication in case the flag http_proactive_auth is
set.

We also take care to read env proxy var according to protocol being
used in the destination url, e.g.  when the url to retrieve is a https
one, then the proxy env var we look at is https_proxy. To make this
possible we now passed destination url parameter to get_active_slot()
and get_curl_handle() functions.

We also read no_proxy env var so to ignore aforementioned proxy env var
if no_proxy contains an asterisk ('*') or contains the host used in url
destination.

Signed-off-by: Nelson Benitez Leon 
Signed-off-by: Junio C Hamano 
---
 http-push.c   | 24 ++++++++++++------------
 http-walker.c |  2 +-
 http.c        | 37 ++++++++++++++++++++++++++++++-------
 http.h        |  2 +-
 remote-curl.c |  4 ++--
 5 files changed, 46 insertions(+), 23 deletions(-)

diff --git a/http-push.c b/http-push.c
index f22f7e43ca..e7bb4cf3d5 100644
--- a/http-push.c
+++ b/http-push.c
@@ -297,7 +297,7 @@ static void start_mkcol(struct transfer_request *request)
 
 	request->url = get_remote_object_url(repo->url, hex, 1);
 
-	slot = get_active_slot();
+	slot = get_active_slot(request->url);
 	slot->callback_func = process_response;
 	slot->callback_data = request;
 	curl_setup_http_get(slot->curl, request->url, DAV_MKCOL);
@@ -417,7 +417,7 @@ static void start_put(struct transfer_request *request)
 	strbuf_add(&buf, request->lock->tmpfile_suffix, 41);
 	request->url = strbuf_detach(&buf, NULL);
 
-	slot = get_active_slot();
+	slot = get_active_slot(request->url);
 	slot->callback_func = process_response;
 	slot->callback_data = request;
 	curl_setup_http(slot->curl, request->url, DAV_PUT,
@@ -438,7 +438,7 @@ static void start_move(struct transfer_request *request)
 	struct active_request_slot *slot;
 	struct curl_slist *dav_headers = NULL;
 
-	slot = get_active_slot();
+	slot = get_active_slot(request->url);
 	slot->callback_func = process_response;
 	slot->callback_data = request;
 	curl_setup_http_get(slot->curl, request->url, DAV_MOVE);
@@ -467,7 +467,7 @@ static int refresh_lock(struct remote_lock *lock)
 
 	dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF | DAV_HEADER_TIMEOUT);
 
-	slot = get_active_slot();
+	slot = get_active_slot(lock->url);
 	slot->results = &results;
 	curl_setup_http_get(slot->curl, lock->url, DAV_LOCK);
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
@@ -882,7 +882,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
 	while (ep) {
 		char saved_character = ep[1];
 		ep[1] = '\0';
-		slot = get_active_slot();
+		slot = get_active_slot(url);
 		slot->results = &results;
 		curl_setup_http_get(slot->curl, url, DAV_MKCOL);
 		if (start_active_slot(slot)) {
@@ -912,7 +912,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
 	dav_headers = curl_slist_append(dav_headers, timeout_header);
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
 
-	slot = get_active_slot();
+	slot = get_active_slot(url);
 	slot->results = &results;
 	curl_setup_http(slot->curl, url, DAV_LOCK, &out_buffer, fwrite_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
@@ -980,7 +980,7 @@ static int unlock_remote(struct remote_lock *lock)
 
 	dav_headers = get_dav_token_headers(lock, DAV_HEADER_LOCK);
 
-	slot = get_active_slot();
+	slot = get_active_slot(lock->url);
 	slot->results = &results;
 	curl_setup_http_get(slot->curl, lock->url, DAV_UNLOCK);
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
@@ -1158,7 +1158,7 @@ static void remote_ls(const char *path, int flags,
 	dav_headers = curl_slist_append(dav_headers, "Depth: 1");
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
 
-	slot = get_active_slot();
+	slot = get_active_slot(url);
 	slot->results = &results;
 	curl_setup_http(slot->curl, url, DAV_PROPFIND,
 			&out_buffer, fwrite_buffer);
@@ -1232,7 +1232,7 @@ static int locking_available(void)
 	dav_headers = curl_slist_append(dav_headers, "Depth: 0");
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
 
-	slot = get_active_slot();
+	slot = get_active_slot(repo->url);
 	slot->results = &results;
 	curl_setup_http(slot->curl, repo->url, DAV_PROPFIND,
 			&out_buffer, fwrite_buffer);
@@ -1409,7 +1409,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
 
 	strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
 
-	slot = get_active_slot();
+	slot = get_active_slot(lock->url);
 	slot->results = &results;
 	curl_setup_http(slot->curl, lock->url, DAV_PUT,
 			&out_buffer, fwrite_null);
@@ -1535,7 +1535,7 @@ static void update_remote_info_refs(struct remote_lock *lock)
 	if (!aborted) {
 		dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
 
-		slot = get_active_slot();
+		slot = get_active_slot(lock->url);
 		slot->results = &results;
 		curl_setup_http(slot->curl, lock->url, DAV_PUT,
 				&buffer, fwrite_null);
@@ -1695,7 +1695,7 @@ static int delete_remote_branch(const char *pattern, int force)
 		return 0;
 	url = xmalloc(strlen(repo->url) + strlen(remote_ref->name) + 1);
 	sprintf(url, "%s%s", repo->url, remote_ref->name);
-	slot = get_active_slot();
+	slot = get_active_slot(url);
 	slot->results = &results;
 	curl_setup_http_get(slot->curl, url, DAV_DELETE);
 	if (start_active_slot(slot)) {
diff --git a/http-walker.c b/http-walker.c
index 51a906e9e3..5d5ae34fce 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -348,7 +348,7 @@ static void fetch_alternates(struct walker *walker, const char *base)
 	 * Use a callback to process the result, since another request
 	 * may fail and need to have alternates loaded before continuing
 	 */
-	slot = get_active_slot();
+	slot = get_active_slot(url);
 	slot->callback_func = process_alternates_response;
 	alt_req.walker = walker;
 	slot->callback_data = &alt_req;
diff --git a/http.c b/http.c
index 8ac8eb6c38..d68bbb28cf 100644
--- a/http.c
+++ b/http.c
@@ -42,6 +42,7 @@ static long curl_low_speed_time = -1;
 static int curl_ftp_no_epsv;
 static const char *curl_http_proxy;
 static const char *curl_cookie_file;
+static struct credential cre_url = CREDENTIAL_INIT;
 static struct credential http_auth = CREDENTIAL_INIT;
 static int http_proactive_auth;
 static const char *user_agent;
@@ -232,7 +233,7 @@ static int has_cert_password(void)
 	return 1;
 }
 
-static CURL *get_curl_handle(void)
+static CURL *get_curl_handle(const char *url)
 {
 	CURL *result = curl_easy_init();
 
@@ -295,6 +296,28 @@ static CURL *get_curl_handle(void)
 	if (curl_ftp_no_epsv)
 		curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
 
+	if (!curl_http_proxy) {
+		const char *env_proxy, *no_proxy;
+		char *env_proxy_var;
+		int read_http_proxy;
+		struct strbuf buf = STRBUF_INIT;
+		credential_from_url(&cre_url, url);
+		strbuf_addf(&buf, "%s_proxy", cre_url.protocol);
+		env_proxy_var = strbuf_detach(&buf, NULL);
+		env_proxy = getenv(env_proxy_var);
+		if (env_proxy) {
+			read_http_proxy = 1;
+			no_proxy = getenv("no_proxy");
+			if (!no_proxy)
+				no_proxy = getenv("NO_PROXY");
+			if (no_proxy && (!strcmp("*", no_proxy) || strstr(no_proxy, cre_url.host)))
+				read_http_proxy = 0;
+
+			if (read_http_proxy)
+				curl_http_proxy = xstrdup(env_proxy);
+		}
+		free(env_proxy_var);
+	}
 	if (curl_http_proxy) {
 		curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
 		curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
@@ -385,7 +408,7 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
 	}
 
 #ifndef NO_CURL_EASY_DUPHANDLE
-	curl_default = get_curl_handle();
+	curl_default = get_curl_handle(url);
 #endif
 }
 
@@ -434,7 +457,7 @@ void http_cleanup(void)
 	ssl_cert_password_required = 0;
 }
 
-struct active_request_slot *get_active_slot(void)
+struct active_request_slot *get_active_slot(const char *url)
 {
 	struct active_request_slot *slot = active_queue_head;
 	struct active_request_slot *newslot;
@@ -472,7 +495,7 @@ struct active_request_slot *get_active_slot(void)
 
 	if (slot->curl == NULL) {
 #ifdef NO_CURL_EASY_DUPHANDLE
-		slot->curl = get_curl_handle();
+		slot->curl = get_curl_handle(url);
 #else
 		slot->curl = curl_easy_duphandle(curl_default);
 #endif
@@ -745,7 +768,7 @@ static int http_request(const char *url, void *result, int target, int options)
 	struct strbuf buf = STRBUF_INIT;
 	int ret;
 
-	slot = get_active_slot();
+	slot = get_active_slot(url);
 	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 
@@ -1090,7 +1113,7 @@ struct http_pack_request *new_http_pack_request(
 		goto abort;
 	}
 
-	preq->slot = get_active_slot();
+	preq->slot = get_active_slot(preq->url);
 	curl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile);
 	curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
 	curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
@@ -1250,7 +1273,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
 		}
 	}
 
-	freq->slot = get_active_slot();
+	freq->slot = get_active_slot(freq->url);
 
 	curl_easy_setopt(freq->slot->curl, CURLOPT_FILE, freq);
 	curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
diff --git a/http.h b/http.h
index 0b61653894..303eafbd2a 100644
--- a/http.h
+++ b/http.h
@@ -73,7 +73,7 @@ extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);
 #endif
 
 /* Slot lifecycle functions */
-extern struct active_request_slot *get_active_slot(void);
+extern struct active_request_slot *get_active_slot(const char *url);
 extern int start_active_slot(struct active_request_slot *slot);
 extern void run_active_slot(struct active_request_slot *slot);
 extern void finish_active_slot(struct active_request_slot *slot);
diff --git a/remote-curl.c b/remote-curl.c
index d159fe7f34..1b5eaf30b7 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -383,7 +383,7 @@ static int probe_rpc(struct rpc_state *rpc)
 	struct strbuf buf = STRBUF_INIT;
 	int err;
 
-	slot = get_active_slot();
+	slot = get_active_slot(rpc->service_url);
 
 	headers = curl_slist_append(headers, rpc->hdr_content_type);
 	headers = curl_slist_append(headers, rpc->hdr_accept);
@@ -440,7 +440,7 @@ static int post_rpc(struct rpc_state *rpc)
 			return err;
 	}
 
-	slot = get_active_slot();
+	slot = get_active_slot(rpc->service_url);
 
 	curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
 	curl_easy_setopt(slot->curl, CURLOPT_POST, 1);

From 6e17b8c16aa6fd535ffae04d332e9b7ee8a927d0 Mon Sep 17 00:00:00 2001
From: Nelson Benitez Leon 
Date: Tue, 13 Mar 2012 15:03:54 +0100
Subject: [PATCH 3222/3720] http: handle proxy proactive authentication

If http_proactive_auth flag is set and there is a username
but no password in the proxy url, then interactively ask for
the password.

This makes possible to not have the password written down in
http_proxy env var or in http.proxy config option.

Also take care that CURLOPT_PROXY don't include username or
password, as we now set them in the new set_proxy_auth() function
where we use their specific cURL options.

Signed-off-by: Nelson Benitez Leon 
Signed-off-by: Junio C Hamano 
---
 http.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/http.c b/http.c
index d68bbb28cf..7215f4976b 100644
--- a/http.c
+++ b/http.c
@@ -44,6 +44,7 @@ static const char *curl_http_proxy;
 static const char *curl_cookie_file;
 static struct credential cre_url = CREDENTIAL_INIT;
 static struct credential http_auth = CREDENTIAL_INIT;
+static struct credential proxy_auth = CREDENTIAL_INIT;
 static int http_proactive_auth;
 static const char *user_agent;
 
@@ -233,6 +234,20 @@ static int has_cert_password(void)
 	return 1;
 }
 
+static void set_proxy_auth(CURL *result)
+{
+	if (proxy_auth.username && proxy_auth.password) {
+#if LIBCURL_VERSION_NUM >= 0x071901
+		curl_easy_setopt(result, CURLOPT_PROXYUSERNAME, proxy_auth.username);
+		curl_easy_setopt(result, CURLOPT_PROXYPASSWORD, proxy_auth.password);
+#else
+		struct strbuf userpwd = STRBUF_INIT;
+		strbuf_addf(&userpwd, "%s:%s", proxy_auth.username, proxy_auth.password);
+		curl_easy_setopt(result, CURLOPT_PROXYUSERPWD, strbuf_detach(&userpwd, NULL));
+#endif
+	}
+}
+
 static CURL *get_curl_handle(const char *url)
 {
 	CURL *result = curl_easy_init();
@@ -319,8 +334,19 @@ static CURL *get_curl_handle(const char *url)
 		free(env_proxy_var);
 	}
 	if (curl_http_proxy) {
-		curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
+		struct strbuf proxyhost = STRBUF_INIT;
+
+		if (!proxy_auth.host) /* check to parse only once */
+			credential_from_url(&proxy_auth, curl_http_proxy);
+
+		if (http_proactive_auth && proxy_auth.username && !proxy_auth.password)
+			/* proxy string has username but no password, ask for password */
+			credential_fill(&proxy_auth);
+
+		strbuf_addf(&proxyhost, "%s://%s", proxy_auth.protocol, proxy_auth.host);
+		curl_easy_setopt(result, CURLOPT_PROXY, strbuf_detach(&proxyhost, NULL));
 		curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+		set_proxy_auth(result);
 	}
 
 	return result;

From 4896c4885e160383bfd460a5eaa9c75cb2f70fbc Mon Sep 17 00:00:00 2001
From: Nelson Benitez Leon 
Date: Tue, 13 Mar 2012 15:04:42 +0100
Subject: [PATCH 3223/3720] http: handle proxy authentication failure (error
 407)

Handle http 407 error code by asking for credentials and
retrying request in case credentials were not present, or
marking credentials as rejected if they were already provided.

Signed-off-by: Nelson Benitez Leon 
Signed-off-by: Junio C Hamano 
---
 http.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/http.c b/http.c
index 7215f4976b..85399bf78e 100644
--- a/http.c
+++ b/http.c
@@ -842,6 +842,15 @@ static int http_request(const char *url, void *result, int target, int options)
 				init_curl_http_auth(slot->curl);
 				ret = HTTP_REAUTH;
 			}
+		} else if (results.http_code == 407) { /* Proxy authentication failure */
+			if (proxy_auth.username && proxy_auth.password) {
+				credential_reject(&proxy_auth);
+				ret = HTTP_NOAUTH;
+			} else {
+				credential_fill(&proxy_auth);
+				set_proxy_auth(slot->curl);
+				ret = HTTP_REAUTH;
+			}
 		} else {
 			if (!curl_errorstr[0])
 				strlcpy(curl_errorstr,

From 2217c38e5bdc2f8d8356f9a5560d0f2fd4e320c5 Mon Sep 17 00:00:00 2001
From: Nelson Benitez Leon 
Date: Tue, 13 Mar 2012 15:05:40 +0100
Subject: [PATCH 3224/3720] http: Avoid limit of retrying request only twice

Current code, after receiving HTTP_REAUTH, only retried
once, so couldn't do step 3 of the following sequence:

  1. We make a request; proxy returns 407, because we didn't give it a
     password. We ask for the password and return HTTP_REAUTH.

  2. We make another request; the proxy passes it to the actual server,
     who returns 401, because we didn't give an http password. We ask
     for the password and return HTTP_REAUTH.

  3. We make a third request, but this time everybody is happy.

Now we retry as long as we keep receiving HTTP_REAUTH, so the previous
sequence correctly completes.

Patch by Jeff King 

Signed-off-by: Nelson Benitez Leon 
Signed-off-by: Junio C Hamano 
---
 http.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 85399bf78e..e537031108 100644
--- a/http.c
+++ b/http.c
@@ -875,10 +875,13 @@ static int http_request(const char *url, void *result, int target, int options)
 static int http_request_reauth(const char *url, void *result, int target,
 			       int options)
 {
-	int ret = http_request(url, result, target, options);
-	if (ret != HTTP_REAUTH)
-		return ret;
-	return http_request(url, result, target, options);
+	int ret;
+
+	do {
+		ret = http_request(url, result, target, options);
+	} while (ret == HTTP_REAUTH);
+
+	return ret;
 }
 
 int http_get_strbuf(const char *url, struct strbuf *result, int options)

From 72d62efe1c6044b25e2e3bdabde3eba2de75db48 Mon Sep 17 00:00:00 2001
From: Nelson Benitez Leon 
Date: Wed, 14 Mar 2012 12:11:43 +0100
Subject: [PATCH 3225/3720] http: rename HTTP_REAUTH to HTTP_AUTH_RETRY

After adding the proxy authentication support in http, the semantics
of HTTP_REAUTH changed more to a retry rather than a re-authentication,
so we rename it to HTTP_AUTH_RETRY.

Signed-off-by: Nelson Benitez Leon 
Signed-off-by: Junio C Hamano 
---
 http.c | 6 +++---
 http.h | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index e537031108..1c71edbfdb 100644
--- a/http.c
+++ b/http.c
@@ -840,7 +840,7 @@ static int http_request(const char *url, void *result, int target, int options)
 			} else {
 				credential_fill(&http_auth);
 				init_curl_http_auth(slot->curl);
-				ret = HTTP_REAUTH;
+				ret = HTTP_AUTH_RETRY;
 			}
 		} else if (results.http_code == 407) { /* Proxy authentication failure */
 			if (proxy_auth.username && proxy_auth.password) {
@@ -849,7 +849,7 @@ static int http_request(const char *url, void *result, int target, int options)
 			} else {
 				credential_fill(&proxy_auth);
 				set_proxy_auth(slot->curl);
-				ret = HTTP_REAUTH;
+				ret = HTTP_AUTH_RETRY;
 			}
 		} else {
 			if (!curl_errorstr[0])
@@ -879,7 +879,7 @@ static int http_request_reauth(const char *url, void *result, int target,
 
 	do {
 		ret = http_request(url, result, target, options);
-	} while (ret == HTTP_REAUTH);
+	} while (ret == HTTP_AUTH_RETRY);
 
 	return ret;
 }
diff --git a/http.h b/http.h
index 303eafbd2a..6e3ea594be 100644
--- a/http.h
+++ b/http.h
@@ -123,7 +123,7 @@ extern char *get_remote_object_url(const char *url, const char *hex,
 #define HTTP_MISSING_TARGET	1
 #define HTTP_ERROR		2
 #define HTTP_START_FAILED	3
-#define HTTP_REAUTH	4
+#define HTTP_AUTH_RETRY	4
 #define HTTP_NOAUTH	5
 
 /*

From 571e0e753dfb67cf005c6bbae64e161937797898 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Fri, 23 Mar 2012 10:58:37 +0100
Subject: [PATCH 3226/3720] am: Use cat instead of echo to avoid DOS
 line-endings (fixes t4150)

Along the lines of 05d0e3b and f33946d, use cat instead of echo to avoid
line ending mismatches in the test result of "am empty-file does not
infloop" which make the test fail.

Signed-off-by: Sebastian Schuberth 
---
 git-am.sh | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/git-am.sh b/git-am.sh
index ef7191e562..a499e147b0 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -176,7 +176,9 @@ It does not apply to blobs recorded in its index.")"
 }
 
 clean_abort () {
-	test $# = 0 || echo >&2 "$@"
+	test $# = 0 || cat >&2 <
Date: Sat, 14 Jan 2012 19:55:36 +0100
Subject: [PATCH 3227/3720] bash-completion: don't add quoted space for ZSH
 (fix regression)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit a31e626 (completion: optimize refs completion) introduced a
regression for ZSH users: ref names were completed with a quoted trailing
space (i.e. "git checkout ma" completes to "git checkout master\ "). The
space is convenient for bash users since we use "-o nospace", but a
quoted space is worse than nothing. The absence of trailing space for ZSH
is a long-standing issue, that this patch is not fixing. We just fix the
regression by not appending a space when the shell is ZSH.

Original-patch-by: SZEDER Gábor 
Reported-by: Stefan Haller 
Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 contrib/completion/git-completion.bash | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 31f714da92..8d92094e42 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -509,6 +509,13 @@ __gitcomp ()
 __gitcomp_nl ()
 {
 	local IFS=$'\n'
+
+	# ZSH would quote the trailing space added with -S. bash users
+	# will appreciate the extra space to compensate the use of -o nospace.
+	if [ -n "${ZSH_VERSION-}" ] && [ "$suffix" = " " ]; then
+		suffix=""
+	fi
+
 	COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
 }
 

From 0eb988904c8ebd130b96322dc1c9133e79aebda3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 3228/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index be1957a5e9..073c3f67e6 100644
--- a/Makefile
+++ b/Makefile
@@ -1194,16 +1194,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 1d396a81776e76702ac1ffc117713b79bb3ddb1b Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 3229/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index fb386abc51..a6f38e6ca0 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -184,6 +184,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 0e708c478f..838d06824a 100644
--- a/cache.h
+++ b/cache.h
@@ -605,6 +605,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..cc1b34999d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..699a3dd395 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -113,10 +113,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -318,6 +315,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index 68d32940f3..1759695d16 100644
--- a/config.c
+++ b/config.c
@@ -752,6 +752,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index d7e6c65763..d827d9e71d 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index ed11ad8119..14fa4e117a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -595,4 +595,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From fada95a7eb5a6007df95a41261a65706b3606ea0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 3230/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index cc1b34999d..665f6abc40 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From ade9eff183a4e6a659c6e8dd26153ca513413bd8 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 3231/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 13e143f894f0649e621d3dbf2057fb5e3b3f6002 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 3232/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 674b65a54336ed3b0d2011d5e0e826fc3bd850ae Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 3233/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 116eff9bc207fd53f50dd4b931e972b1b90cacd8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 3234/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 651b740043..6060aab3d7 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9575,7 +9575,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 805627e4cc876b43e26ff8b8b475e21acc6d88dd Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 3235/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From c57ff98b36f65054f65bf8b59c8e7779c9485d9a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 3236/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From d1bc99481f7a3ee53dbb481aca9df4873392d382 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 3237/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index a6f38e6ca0..49a24e5fb2 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1738,6 +1738,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 0afb8b2896..1b2bf5fe66 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -89,7 +91,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -410,6 +417,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -441,6 +486,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -469,6 +521,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b5417cc951..2482796454 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -995,4 +995,40 @@ test_expect_success 'push --prune refspec' '
 	! check_push_result $the_first_commit tmp/foo tmp/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 1616777cad554806da2e5af8aaa191200097125a Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 3238/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index ef30c557c7..c42fb2a7aa 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 884364790f1adac414ab4c8bc7200c6da658fdd4 Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 3239/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index c42fb2a7aa..03292fd832 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 758391b8931b3ccd86950e3d714472f3bcc6ddf2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 3240/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 33c8820af6..c836ad063c 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -169,7 +169,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = given_config_file;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 665f6abc40..e5f1c36995 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 699a3dd395..ec5c25c36d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -349,3 +349,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index 1759695d16..53fd956a88 100644
--- a/config.c
+++ b/config.c
@@ -960,7 +960,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 14fa4e117a..5911e8f7eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -599,4 +599,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index 6f2aa699ad..4cb0585cde 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 1d70afdbea33609416453604690fed0355aea293 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 3241/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 4da0ddafc4..ef7191e562 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -564,7 +564,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -736,7 +737,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -812,7 +814,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -836,7 +838,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From 82332f82bde4d698456f8a08be46bf003d38c8b4 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 3242/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index b7d7100c4e..ca782c386a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From f408e2faf4fcdc5ec2e2a4d0b32e51578a3d9077 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 3243/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 838d06824a..91f4af3195 100644
--- a/cache.h
+++ b/cache.h
@@ -759,7 +759,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index e5f1c36995..39ce7b446d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index ec5c25c36d..9111ce66e7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -309,6 +309,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 5911e8f7eb..39866a76c2 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 4cb0585cde..242074b1cf 100644
--- a/path.c
+++ b/path.c
@@ -660,10 +660,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 2b48997442c17cd953fbdcc9689d5fcd8040c2e1 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 3244/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index c836ad063c..e24586efa5 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;

From da8dfead977168d2fef718082faff0aac1747611 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 3245/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 39ce7b446d..71adbc497a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 9cc1a4285fb61fe7455023eb54280aa5a0509c75 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 3246/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 4d1917f6884a3fce4edeae8aad3be385c5c07fad Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 3247/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 6060aab3d7..86c26737d0 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -394,7 +394,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9575,18 +9575,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9597,6 +9586,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 1414047c9606a0292808f74d2ac4f98fd34b5396 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 3248/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 71adbc497a..fe3cae3a38 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 086e7b6d0b2217b610245a6e166afcb61ac13c92 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 3249/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9111ce66e7..60e281a7fe 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From 394e0e035901df97eb6356122745e386bea8d218 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 3250/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 1dac07f6449eebd495c85dec01964da2ed869666 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 3251/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 2315a871adb33c3539ae3b68aa028e196a82a49e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 3252/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index cea8756866..9be97ab9ae 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From 6e1db66458b42f93bd84dcfce57a04ccbe1526aa Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 3253/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a8b5fad266..ec97589687 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4434,6 +4434,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 4217fc4c1389aff033ce74dcca75b768a5d482ca Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 3254/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index ec97589687..3c2284f611 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4449,7 +4449,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 17709f3ccbd04053b363445ab691af5378bd5758 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 3255/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 3e51d6cbe9..3013849db0 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -140,6 +141,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -147,17 +160,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 5b14da50a148d180b8ddb7519ccd4450f4e13a0b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 3256/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 1b2bf5fe66..b648c14a86 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -420,7 +420,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 16a444f6ee0cdd83bd2d54ac4445e3e1330fb42a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 3257/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 643938d905..cda17f775a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -162,6 +163,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -172,6 +189,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->source.identifier))
+			continue;
+
 		opt->output_priv = w;
 		hit |= grep_source(opt, &w->source);
 		grep_source_clear_data(&w->source);
@@ -418,6 +438,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -883,6 +906,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From b046d761a1e83fd1134551a64c8fa05fe3a2b9b7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 3258/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 073c3f67e6..c7c90e5f33 100644
--- a/Makefile
+++ b/Makefile
@@ -308,7 +308,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From c259b89a3b9fd4812ad1056f5af7df08d6f76e77 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 3259/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index fe3cae3a38..f86800680c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From bece3b94a5b5e49c0bca300230d231b5c86afaa5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 3260/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c7c90e5f33..5223417b99 100644
--- a/Makefile
+++ b/Makefile
@@ -2093,7 +2093,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2133,6 +2133,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 5b5eee14103061ce49a1b06a3a5c3bdd1875ff95 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 3261/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..18a93cba9f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 42499872f8627f16700bc3ee34159b0d5b56417a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 3262/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index cda17f775a..3af417e76c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -974,6 +974,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From d7e88664f2964551ca3d9bed06aa601dcbf99e1d Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 3263/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index 497f420178..266c1236ff 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 7b32eeae4e4d3d9b84c394544e6f3eda282277d5 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 3264/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f86800680c..61a1230433 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 5975e7e9bddc6bd2b039ebcb45408f54f1925513 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 3265/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 44d3283b9c2bfd07447c895ccbd67117b62f04e0 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 3266/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 3267/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index efc86ad4e0..5bec652114 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -832,12 +832,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 3268/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 765be52368c2e8073b3d28f134a0d10d040ffb8d Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 3269/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 5d8e4e6c89..d9fc4be050 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 3270/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 5223417b99..7879caa174 100644
--- a/Makefile
+++ b/Makefile
@@ -1188,6 +1188,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1281,6 +1282,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 051fa8d6c095225f5f1869dd922ab5666d66d56b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 3271/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 105b37fce4a1c639232cc3b261b8ce92e3b976d3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 3272/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From 0412a11a9cf579e475f5af2c0ee574daf7598d79 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 3273/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 8ddb5c8a2c9406544d93159b8238d2ac3f5313de Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 3274/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 8cfded7885aad01379fc594b5173dd735ffe098d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 3275/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 61a1230433..398c11f175 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 2e087b0de9a9f7e1fe9877df343d4389e4fe994a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 3276/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 398c11f175..8565118abd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 60e281a7fe..da9c53583a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From c08cbfda21ef61acc3d3cb172c9cfecd45e88386 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 3277/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8565118abd..1b40ff2373 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 50204165750735331d71a56530f8e3601a95f520 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 3278/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 3c2284f611..e032b69aff 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6812,7 +6812,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6860,6 +6872,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From a5c4306adf6c53bd11a8e9ad25c040fac673a0d6 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 3279/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e032b69aff..5dbbcfa0ba 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4434,7 +4434,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 12416bd0c8595ab005f2ef96aa04e3ff1d8ae14b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 3280/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 5dbbcfa0ba..14a133ae00 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6925,7 +6925,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From db7439099fb28cf5ef474f889f847b1b0dce196d Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 3281/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1b40ff2373..952a2a6819 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From afa2a9c47f3a666c57a4f85e1b6e6196b6728cf0 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 3282/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index da9c53583a..1f9f35f63d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 5f04d66efda7107ed39b3986c9736698e134502e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 3283/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 2a10047eb7..be1b098be0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -113,7 +114,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -278,7 +284,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From 2d764c8659ceeee8bdf7a6917188cbcb060d83cd Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 3284/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 49a24e5fb2..1e76b4c2e1 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -714,6 +714,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index be1b098be0..34b47c4fb2 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From d8c31c631e3af7e1f4dd30c8cc9baddc77b11f2f Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 3285/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1f9f35f63d..407bad231b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 39866a76c2..76c5eef420 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From 6515e75c549aa9ac70d3f59b6fba28da35a0b72e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 3286/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From 19525c6aba2b72f7741b1750b028e1e7ef50ac51 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 3287/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 7879caa174..3ad3062305 100644
--- a/Makefile
+++ b/Makefile
@@ -1186,6 +1186,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From b8cd619b8e5baa95358b861c1c900343558155a6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 3288/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From 80fd96e8c2d73e441290927a8099e262877fc733 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 3289/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3ad3062305..4dc9256967 100644
--- a/Makefile
+++ b/Makefile
@@ -1264,7 +1264,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From afb826b05a68c2b6901196fdcf5ae804bf8b75e1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 3290/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 4dc9256967..c82f297f0f 100644
--- a/Makefile
+++ b/Makefile
@@ -1301,6 +1301,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From b2fc555862bd8647b3d05a9a098154ca12f72a0b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 3291/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From b54a4a3559a91751f7072af97a886b9cc98351ab Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 18:15:31 +0100
Subject: [PATCH 3292/3720] Windows/i18n: rename $path to prevent clashes with
 $PATH

Environment variables on Windows are case-insensitive. Rename '$path' in
all calls to eval_gettext to $modulepath so that it is not mistakenly
expanded to the value of the $PATH variable.

[jes: this happens to fix t7406/t7407 on Windows]
[pt: squashed in fix for substitution order error that broke t7400]

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
---
 git-submodule.sh | 52 ++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index dccd0f663a..efb0cfdfe9 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -105,7 +105,7 @@ module_name()
 	name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
 	test -z "$name" &&
-	die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+	die "$(modulepath=$path eval_gettext "No submodule mapping found in .gitmodules for path '\$modulepath'")"
 	echo "$name"
 }
 
@@ -146,7 +146,7 @@ module_clone()
 		mkdir -p "$gitdir_base"
 		git clone $quiet -n ${reference:+"$reference"} \
 			--separate-git-dir "$gitdir" "$url" "$path" ||
-		die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+		die "$(modulepath=$path eval_gettext "Clone of '\$url' into submodule path '\$modulepath' failed")"
 	fi
 
 	a=$(cd "$gitdir" && pwd)/
@@ -261,13 +261,13 @@ cmd_add()
 			s|/*$||
 		')
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
-	die "$(eval_gettext "'\$path' already exists in the index")"
+	die "$(modulepath=$path eval_gettext "'\$modulepath' already exists in the index")"
 
 	if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
 	then
 		cat >&2 </dev/null) &&
 					 test -z "$rev") || git-fetch)) ||
-				die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
+				die "$(modulepath=$path eval_gettext "Unable to fetch in submodule path '\$modulepath'")"
 			fi
 
 			# Is this something we just cloned?
@@ -564,20 +564,20 @@ Maybe you want to use 'update --init'?")"
 			case "$update_module" in
 			rebase)
 				command="git rebase"
-				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to rebase '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': rebased into '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			merge)
 				command="git merge"
-				die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to merge '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': merged in '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			*)
 				command="git checkout $subforce -q"
-				die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to checkout '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': checked out '\$sha1'")"
 				;;
 			esac
 
@@ -599,7 +599,7 @@ Maybe you want to use 'update --init'?")"
 			res=$?
 			if test $res -gt 0
 			then
-				die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+				die_msg="$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 				if test $res -eq 1
 				then
 					err="${err};$die_msg"
@@ -926,7 +926,7 @@ cmd_status()
 				cd "$path" &&
 				eval cmd_status "$orig_args"
 			) ||
-			die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+			die "$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 		fi
 	done
 }

From a09c0041b817ae6f8b7e1b37eed92ac495278105 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Mon, 30 Jan 2012 23:38:42 +0000
Subject: [PATCH 3293/3720] gitk: fix setting font display with new tabbed
 dialog layout.

The changes to the dialog window tree broke the preview of the selected
font on the button. This corrects that issue.

Signed-off-by: Pat Thoyts 
---
 gitk-git/gitk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 86c26737d0..ce24487789 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10811,7 +10811,7 @@ proc fontok {} {
     if {$fontparam(slant) eq "italic"} {
 	lappend fontpref($f) "italic"
     }
-    set w $prefstop.$f
+    set w $prefstop.notebook.fonts.$f
     $w conf -text $fontparam(family) -font $fontpref($f)
 
     fontcan

From cdabadb58522ff7945058f5f80b198ccbe83ec02 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 3 Feb 2012 00:12:04 -0600
Subject: [PATCH 3294/3720] Teach 'git remote' that the config var
 branch.*.rebase can be 'interactive'

Signed-off-by: Johannes Schindelin 
---
 builtin/remote.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index fec92bc66e..7b37a23d97 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -253,7 +253,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	int rebase;
+	enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
 };
 
 static struct string_list branch_list;
@@ -310,7 +310,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			}
 			string_list_append(&info->merge, xstrdup(value));
 		} else
-			info->rebase = git_config_bool(orig_key, value);
+			info->rebase = value && *value == 'i' ?
+				INTERACTIVE_REBASE :
+				(git_config_bool(orig_key, value) ?
+				 NORMAL_REBASE : NO_REBASE);
 	}
 	return 0;
 }
@@ -994,7 +997,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf("rebases onto remote %s\n", merge->items[0].string);
+		printf("rebases %sonto remote %s\n",
+			branch_info->rebase == INTERACTIVE_REBASE ?
+			"interactively " : "", merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf(" merges with remote %s\n", merge->items[0].string);

From 2094b6a8e95aaa57553ee7b34eb65490cad304cd Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:28:37 +0100
Subject: [PATCH 3295/3720] git-gui: fix encoding in git-gui file browser

Assume git tree objects (i.e. output of git-ls-tree) are encoded in system
encoding, for display in the git-gui file browser.

Signed-off-by: Karsten Blees 
---
 git-gui/lib/browser.tcl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 0328338fda..4fca8fb13c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary -encoding binary
+	fconfigure $fd -blocking 0 -translation binary
 	fileevent $fd readable [cb _read $fd]
 }
 

From d73116bbddadd46d34ad70e001c7602b64f35648 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:38:07 +0100
Subject: [PATCH 3296/3720] gitk: fix file name encoding in diff hunk headers

Decode file names from system encoding in all diff hunk header lines, not
just the first (i.e. print nice file names in 'rename from' / 'rename to' /
'Binary files' lines, too).

Signed-off-by: Karsten Blees 
---
 gitk-git/gitk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index ce24487789..808ccc84d7 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7855,6 +7855,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
+	    set line [encoding convertfrom $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {

From a7e0a6f3b88f535e92bc0c646218e528091576f7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 19:06:41 +0100
Subject: [PATCH 3297/3720] Revert "Windows: teach getenv to do a
 case-sensitive search"

This reverts commit df599e9612788b728ce43a03159b85f1fe624d6a.

As of 5e9637c6 "i18n: add infrastructure for translating Git with gettext",
eval_gettext uses MinGW envsubst.exe instead of git-sh-i18n--envsubst.exe
for variable substitution. This breaks git-submodule.sh messages and tests,
as envsubst.exe doesn't support case-sensitive environment lookup (the same
is true for almost everything on Windows, including MSys and Cygwin tools).

30a615ac "Windows/i18n: rename $path to prevent clashes with $PATH" renames
the conflicting variable in git-submodule.sh, so that it works on Windows
(i.e. with case-insensitive environment, regardless of the toolset).

Revert to the documented behaviour of case-insensitive environment on
Windows.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 952a2a6819..1135b4bb78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1182,31 +1182,14 @@ char **make_augmented_environ(const char *const *vars)
 }
 
 #undef getenv
-
-/*
- * The system's getenv looks up the name in a case-insensitive manner.
- * This version tries a case-sensitive lookup and falls back to
- * case-insensitive if nothing was found.  This is necessary because,
- * as a prominent example, CMD sets 'Path', but not 'PATH'.
- * Warning: not thread-safe.
- */
-static char *getenv_cs(const char *name)
-{
-	size_t len = strlen(name);
-	int i = lookup_env(environ, name, len);
-	if (i >= 0)
-		return environ[i] + len + 1;	/* skip past name and '=' */
-	return getenv(name);
-}
-
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv_cs(name);
+	char *result = getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv_cs("TMP");
+		result = getenv("TMP");
 		if (!result)
-			result = getenv_cs("TEMP");
+			result = getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */

From ed1e3f52ba874338187926e6fc626e606982d8ae Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:19:31 +0100
Subject: [PATCH 3298/3720] Revert "mingw.c: move definition of mingw_getenv
 down"

This reverts commit 06bc4b796ad69ba93f0a8c451368602e0553c2d3.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1135b4bb78..649c6857dd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -180,7 +180,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	vsnprintf(question, sizeof(question), format, args);
 	va_end(args);
 
-	if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
+	if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
 		retry_hook[1] = question;
 		return !run_command_v_opt(retry_hook, 0);
 	}
@@ -665,6 +665,23 @@ char *mingw_getcwd(char *pointer, int len)
 	return ret;
 }
 
+#undef getenv
+char *mingw_getenv(const char *name)
+{
+	char *result = getenv(name);
+	if (!result && !strcmp(name, "TMPDIR")) {
+		/* on Windows it is TMP and TEMP */
+		result = getenv("TMP");
+		if (!result)
+			result = getenv("TEMP");
+	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
+	return result;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -764,7 +781,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-	char *p, **path, *envpath = mingw_getenv("PATH");
+	char *p, **path, *envpath = getenv("PATH");
 	int i, n = 0;
 
 	if (!envpath || !*envpath)
@@ -1181,23 +1198,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-	char *result = getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
-		if (!result)
-			result = getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From d0fac781e55c0e69afa76bdd3fe9fe876fbd7f00 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:24:19 +0100
Subject: [PATCH 3299/3720] Win32: Thread-safe windows console output

Winansi.c has many static variables that are accessed and modified from
the [v][f]printf / fputs functions overridden in the file. This may cause
multi threaded git commands that print to the console to produce corrupted
output or even crash.

Additionally, winansi.c doesn't override all functions that can be used to
print to the console (e.g. fwrite, write, fputc are missing), so that ANSI
escapes don't work properly for some git commands (e.g. git-grep).

Instead of doing ANSI emulation in just a few wrapped functions on top of
the IO API, let's plug into the IO system and take advantage of the thread
safety inherent to the IO system.

Redirect stdout and stderr to a pipe if they point to the console. A
background thread reads from the pipe, handles ANSI escape sequences and
UTF-8 to UTF-16 conversion, then writes to the console.

The pipe-based stdout and stderr replacements must be set to unbuffered, as
MSVCRT doesn't support line buffering and fully buffered streams are
inappropriate for console output.

Due to the byte-oriented pipe, ANSI escape sequences and multi-byte UTF-8
sequences can no longer be expected to arrive in one piece. Replace the
string-based ansi_emulate() with a simple stateful parser (this also fixes
colored diff hunk headers, which were broken as of commit 2efcc977).

Override isatty to return true for the pipes redirecting to the console.

Exec/spawn obtain the original console handle to pass to the next process
via winansi_get_osfhandle().

All other overrides are gone, the default stdio implementations work as
expected with the piped stdout/stderr descriptors.

Global variables are either initialized on startup (single threaded) or
exclusively modified by the background thread. Threads communicate through
the pipe, no further synchronization is necessary.

The background thread is terminated by disonnecting the pipe after flushing
the stdio and pipe buffers. This doesn't work for anonymous pipes (created
via CreatePipe), as DisconnectNamedPipe only works on the read end, which
discards remaining data. Thus we have to setup the pipe manually, with the
write end beeing the server (opened with CreateNamedPipe) and the read end
the client (opened with CreateFile).

Limitations: doesn't track reopened or duped file descriptors, i.e.:
- fdopen(1/2) returns fully buffered streams
- dup(1/2), dup2(1/2) returns normal pipe descriptors (i.e. isatty() =
  false, winansi_get_osfhandle won't return the original console handle)

Currently, only the git-format-patch command uses xfdopen(xdup(1)) (see
"realstdout" in builtin/log.c), but works well with these limitations.

Many thanks to Atsushi Nakagawa  for suggesting and
reviewing the thread-exit-mechanism.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c   |   9 +-
 compat/mingw.h   |  12 +-
 compat/winansi.c | 420 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 282 insertions(+), 159 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 649c6857dd..190e7b7681 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -917,9 +917,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	memset(&si, 0, sizeof(si));
 	si.cb = sizeof(si);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-	si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-	si.hStdError = (HANDLE) _get_osfhandle(fherr);
+	si.hStdInput = winansi_get_osfhandle(fhin);
+	si.hStdOutput = winansi_get_osfhandle(fhout);
+	si.hStdError = winansi_get_osfhandle(fherr);
 
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
@@ -1878,4 +1878,7 @@ void mingw_startup()
 	_setmode(_fileno(stdin), _O_BINARY);
 	_setmode(_fileno(stdout), _O_BINARY);
 	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
 }
diff --git a/compat/mingw.h b/compat/mingw.h
index 407bad231b..2683adcaf7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -288,14 +288,10 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-int winansi_vfprintf(FILE *stream, const char *format, va_list list);
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
-#define vfprintf winansi_vfprintf
+void winansi_init(void);
+int winansi_isatty(int fd);
+HANDLE winansi_get_osfhandle(int fd);
+#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index bec6713b74..a3e4d88295 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,18 +4,13 @@
 
 #undef NOGDI
 #include "../git-compat-util.h"
-#include 
 #include 
 #include 
 
 /*
  Functions to be wrapped:
 */
-#undef printf
-#undef fprintf
-#undef fputs
-#undef vfprintf
-/* TODO: write */
+#undef isatty
 
 /*
  ANSI codes used by git: m, K
@@ -28,7 +23,10 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
-static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hwrite1 = INVALID_HANDLE_VALUE, hwrite2 = INVALID_HANDLE_VALUE;
+static HANDLE hconsole1, hconsole2;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -44,27 +42,19 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void print_font_warning(void)
+static void warn_if_raster_font(void)
 {
-	warning("Your console font probably doesn\'t support Unicode. If "
-		"you experience strange characters in the output, consider "
-		"switching to a TrueType font such as Lucida Console!");
-}
-
-static void check_truetype_font(void)
-{
-	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't do this twice */
-	if (truetype_font_checked)
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
 		return;
-	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
+			GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);
@@ -73,8 +63,8 @@ static void check_truetype_font(void)
 	} else {
 		/* pre-Vista: check default console font in registry */
 		HKEY hkey;
-		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
-				KEY_READ, &hkey)) {
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+				0, KEY_READ, &hkey)) {
 			DWORD size = sizeof(fontFamily);
 			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
 					(LPVOID) &fontFamily, &size);
@@ -82,61 +72,63 @@ static void check_truetype_font(void)
 		}
 	}
 
-	if (!(fontFamily & TMPF_TRUETYPE))
-		atexit(print_font_warning);
+	if (!(fontFamily & TMPF_TRUETYPE)) {
+		const wchar_t *msg = L"\nWarning: Your console font probably "
+			L"doesn\'t support Unicode. If you experience strange "
+			L"characters in the output, consider switching to a "
+			L"TrueType font such as Lucida Console!\n";
+		WriteConsoleW(console, msg, wcslen(msg), NULL, NULL);
+	}
 }
 
-static int is_console(FILE *stream)
+static int is_console(int fd)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
 	HANDLE hcon;
 
 	static int initialized = 0;
 
-	/* use cached value if stream hasn't changed */
-	if (stream == last_stream)
-		return console != NULL;
-
-	last_stream = stream;
-	console = NULL;
-
-	/* get OS handle of the stream */
-	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	/* get OS handle of the file descriptor */
+	hcon = (HANDLE) _get_osfhandle(fd);
 	if (hcon == INVALID_HANDLE_VALUE)
 		return 0;
 
+	/* check if its a device (i.e. console, printer, serial port) */
+	if (GetFileType(hcon) != FILE_TYPE_CHAR)
+		return 0;
+
 	/* check if its a handle to a console output screen buffer */
 	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
+	/* initialize attributes */
 	if (!initialized) {
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
 	}
 
-	console = hcon;
 	return 1;
 }
 
-static int write_console(const char *str, size_t len)
-{
-	/* convert utf-8 to utf-16, write directly to console */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
-	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
-	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
 
+static void write_console(unsigned char *str, size_t len)
+{
+	/* only called from console_thread, so a static buffer will do */
+	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+
+	/* convert utf-8 to utf-16 */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
+			ARRAY_SIZE(wbuf));
+
+	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/*
-	 * if non-ascii characters are printed, check that the current console
-	 * font supports this
-	 */
+	/* remember if non-ascii characters are printed */
 	if (wlen != len)
-		check_truetype_font();
-
-	/* return original (utf-8 encoded) length */
-	return len;
+		non_ascii_used = 1;
 }
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
@@ -182,18 +174,13 @@ static void erase_in_line(void)
 		&dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-	const char *func;
-	size_t len = strspn(str, "0123456789;");
-	func = str + len;
-
-	switch (*func) {
+	int i;
+	switch (func) {
 	case 'm':
-		do {
-			long val = strtol(str, (char **)&str, 10);
-			switch (val) {
+		for (i = 0; i < paramlen; i++) {
+			switch (params[i]) {
 			case 0: /* reset */
 				attr = plain_attr;
 				negative = 0;
@@ -316,9 +303,7 @@ static const char *set_attr(const char *str)
 				/* Unsupported code */
 				break;
 			}
-			str++;
-		} while (*(str-1) == ';');
-
+		}
 		set_console_attr();
 		break;
 	case 'K':
@@ -328,112 +313,251 @@ static const char *set_attr(const char *str)
 		/* Unsupported code */
 		break;
 	}
-
-	return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+	TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-	int rv = 0;
-	const char *pos = str;
+	unsigned char buffer[BUFFER_SIZE];
+	DWORD bytes;
+	int start, end = 0, c, parampos = 0, state = TEXT;
+	int params[MAX_PARAMS];
 
-	fflush(stream);
+	while (1) {
+		/* read next chunk of bytes from the pipe */
+		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+				NULL)) {
+			/* exit if pipe has been closed or disconnected */
+			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+					GetLastError() == ERROR_BROKEN_PIPE)
+				break;
+			/* ignore other errors */
+			continue;
+		}
 
-	while (*pos) {
-		pos = strstr(str, "\033[");
-		if (pos) {
-			size_t len = pos - str;
+		/* scan the bytes and handle ANSI control codes */
+		bytes += end;
+		start = end = 0;
+		while (end < bytes) {
+			c = buffer[end++];
+			switch (state) {
+			case TEXT:
+				if (c == ESCAPE) {
+					/* print text seen so far */
+					if (end - 1 > start)
+						write_console(buffer + start,
+							end - 1 - start);
 
-			if (len) {
-				size_t out_len = write_console(str, len);
-				rv += out_len;
-				if (out_len < len)
-					return rv;
+					/* then start parsing escape sequence */
+					start = end - 1;
+					memset(params, 0, sizeof(params));
+					parampos = 0;
+					state = ESCAPE;
+				}
+				break;
+
+			case ESCAPE:
+				/* continue if "\033[", otherwise bail out */
+				state = (c == BRACKET) ? BRACKET : TEXT;
+				break;
+
+			case BRACKET:
+				/* parse [0-9;]* into array of parameters */
+				if (c >= '0' && c <= '9') {
+					params[parampos] *= 10;
+					params[parampos] += c - '0';
+				} else if (c == ';') {
+					/*
+					 * next parameter, bail out if out of
+					 * bounds
+					 */
+					parampos++;
+					if (parampos >= MAX_PARAMS)
+						state = TEXT;
+				} else {
+					/*
+					 * end of escape sequence, change
+					 * console attributes
+					 */
+					set_attr(c, params, parampos + 1);
+					start = end;
+					state = TEXT;
+				}
+				break;
+			}
+		}
+
+		/* print remaining text unless parsing an escape sequence */
+		if (state == TEXT && end > start) {
+			/* check for incomplete UTF-8 sequences and fix end */
+			if (buffer[end - 1] >= 0x80) {
+				if (buffer[end -1] >= 0xc0)
+					end--;
+				else if (end - 1 > start &&
+						buffer[end - 2] >= 0xe0)
+					end -= 2;
+				else if (end - 2 > start &&
+						buffer[end - 3] >= 0xf0)
+					end -= 3;
 			}
 
-			str = pos + 2;
-			rv += 2;
+			/* print remaining complete UTF-8 sequences */
+			if (end > start)
+				write_console(buffer + start, end - start);
 
-			pos = set_attr(str);
-			rv += pos - str;
-			str = pos;
+			/* move remaining bytes to the front */
+			if (end < bytes)
+				memmove(buffer, buffer + end, bytes - end);
+			end = bytes - end;
 		} else {
-			size_t len = strlen(str);
-			rv += write_console(str, len);
-			return rv;
+			/* all data has been consumed, mark buffer empty */
+			end = 0;
 		}
 	}
-	return rv;
+
+	/* check if the console font supports unicode */
+	warn_if_raster_font();
+
+	CloseHandle(hread);
+	return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-	int rv;
+	/* flush all streams */
+	_flushall();
 
-	if (!is_console(stream))
-		return fputs(str, stream);
+	/* signal console thread to exit */
+	FlushFileBuffers(hwrite);
+	DisconnectNamedPipe(hwrite);
 
-	rv = ansi_emulate(str, stream);
+	/* wait for console thread to copy remaining data */
+	WaitForSingleObject(hthread, INFINITE);
 
-	if (rv >= 0)
-		return 0;
+	/* cleanup handles... */
+	if (hwrite1 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite1);
+	if (hwrite2 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite2);
+	CloseHandle(hwrite);
+	CloseHandle(hthread);
+}
+
+static void die_lasterr(const char *fmt, ...)
+{
+	va_list params;
+	va_start(params, fmt);
+	errno = err_win_to_posix(GetLastError());
+	die_errno(fmt, params);
+	va_end(params);
+}
+
+static HANDLE duplicate_handle(HANDLE hnd)
+{
+	HANDLE hresult, hproc = GetCurrentProcess();
+	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+			DUPLICATE_SAME_ACCESS))
+		die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+	return hresult;
+}
+
+static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+{
+	/* get original console handle */
+	int fd = _fileno(stream);
+	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
+	if (hcon == INVALID_HANDLE_VALUE)
+		die_errno("_get_osfhandle(%i) failed", fd);
+
+	/* save a copy to phcon and console (used by the background thread) */
+	console = *phcon = duplicate_handle(hcon);
+
+	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
+	if (_dup2(new_fd, fd))
+		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+
+	/* no buffering, or stdout / stderr will be out of sync */
+	setbuf(stream, NULL);
+	return (HANDLE) _get_osfhandle(fd);
+}
+
+void winansi_init(void)
+{
+	int con1, con2, hwrite_fd;
+	char name[32];
+
+	/* check if either stdout or stderr is a console output screen buffer */
+	con1 = is_console(1);
+	con2 = is_console(2);
+	if (!con1 && !con2)
+		return;
+
+	/* create a named pipe to communicate with the console thread */
+	sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+	hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+	if (hwrite == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateNamedPipe failed");
+
+	hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (hread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateFile for named pipe failed");
+
+	/* start console spool thread on the pipe's read end */
+	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+	if (hthread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateThread(console_thread) failed");
+
+	/* schedule cleanup routine */
+	if (atexit(winansi_exit))
+		die_errno("atexit(winansi_exit) failed");
+
+	/* create a file descriptor for the write end of the pipe */
+	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
+	if (hwrite_fd == -1)
+		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
+
+	/* redirect stdout / stderr to the pipe */
+	if (con1)
+		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+	if (con2)
+		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
+
+	/* close pipe file descriptor (also closes the duped hwrite) */
+	close(hwrite_fd);
+}
+
+static int is_same_handle(HANDLE hnd, int fd)
+{
+	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
+}
+
+/*
+ * Return true if stdout / stderr is a pipe redirecting to the console.
+ */
+int winansi_isatty(int fd)
+{
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return 1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return 1;
 	else
-		return EOF;
+		return isatty(fd);
 }
 
-int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-	int len, rv;
-	char small_buf[256];
-	char *buf = small_buf;
-	va_list cp;
-
-	if (!is_console(stream))
-		goto abort;
-
-	va_copy(cp, list);
-	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-	va_end(cp);
-
-	if (len > sizeof(small_buf) - 1) {
-		buf = malloc(len + 1);
-		if (!buf)
-			goto abort;
-
-		len = vsnprintf(buf, len + 1, format, list);
-	}
-
-	rv = ansi_emulate(buf, stream);
-
-	if (buf != small_buf)
-		free(buf);
-	return rv;
-
-abort:
-	rv = vfprintf(stream, format, list);
-	return rv;
-}
-
-int winansi_fprintf(FILE *stream, const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stream, format, list);
-	va_end(list);
-
-	return rv;
-}
-
-int winansi_printf(const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stdout, format, list);
-	va_end(list);
-
-	return rv;
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return hconsole1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return hconsole2;
+	else
+		return (HANDLE) _get_osfhandle(fd);
 }

From fc4640919f7693b65ebdd66f1ae20aa7d081ab99 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:05:06 +0100
Subject: [PATCH 3300/3720] Win32: add Unicode conversion functions

Add Unicode conversion functions to convert between Windows native UTF-16LE
encoding to UTF-8 and back.

To support repositories with legacy-encoded file names, the UTF-8 to UTF-16
conversion function tries to create valid, unique file names even for
invalid UTF-8 byte sequences, so that these repositories can be checked out
without error.

The current implementation leaves invalid UTF-8 bytes in range 0xa0 - 0xff
as is (producing printable Unicode chars \u00a0 - \u00ff, equivalent to
ISO-8859-1), and converts 0x80 - 0x9f to hex-code (\u0080 - \u009f are
control chars).

The Windows MultiByteToWideChar API was not used as it either drops invalid
UTF-8 sequences (on Win2k/XP; producing non-unique or even empty file
names) or converts them to the replacement char \ufffd (Vista/7; causing
ERROR_INVALID_NAME in subsequent calls to file system APIs).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c |  85 ++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 190e7b7681..8ed43f9bf1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1859,6 +1859,91 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
diff --git a/compat/mingw.h b/compat/mingw.h
index 2683adcaf7..ddb228473b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -326,6 +326,110 @@ void mingw_mark_as_git_dir(const char *dir);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A replacement of main() that adds win32 specific initialization.
  */

From 80b5fc234c90df41d3e853c1995a550ab7de95be Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 18:21:28 +0100
Subject: [PATCH 3301/3720] Win32: Unicode file name support (except dirent)

Replaces Windows "ANSI" APIs dealing with file- or path names with their
Unicode equivalent, adding UTF-8/UTF-16LE conversion as necessary.

The dirent API (opendir/readdir/closedir) is updated in a separate commit.

Adds trivial wrappers for access, chmod and chdir.

Adds wrapper for mktemp (needed for both mkstemp and mkdtemp).

The simplest way to convert a repository with legacy-encoded (e.g. Cp1252)
file names to UTF-8 ist to checkout with an old msysgit version and
"git add --all & git commit" with the new version.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 210 ++++++++++++++++++++++++++++++++++---------------
 compat/mingw.h |  13 +++
 2 files changed, 158 insertions(+), 65 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8ed43f9bf1..5d5f30bd2c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "win32.h"
 #include 
+#include 
 #include "../strbuf.h"
 #include "../run-command.h"
 #include "../cache.h"
@@ -200,14 +201,16 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	}
 }
 
-#undef unlink
 int mingw_unlink(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
 	/* read-only files cannot be removed */
-	chmod(pathname, 0666);
-	while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
 		/*
@@ -223,43 +226,40 @@ int mingw_unlink(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = unlink(pathname);
+	       ret = _wunlink(wpathname);
 	return ret;
 }
 
-static int is_dir_empty(const char *path)
+static int is_dir_empty(const wchar_t *wpath)
 {
-	struct strbuf buf = STRBUF_INIT;
-	WIN32_FIND_DATAA findbuf;
+	WIN32_FIND_DATAW findbuf;
 	HANDLE handle;
-
-	strbuf_addf(&buf, "%s\\*", path);
-	handle = FindFirstFileA(buf.buf, &findbuf);
-	if (handle == INVALID_HANDLE_VALUE) {
-		strbuf_release(&buf);
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
 		return GetLastError() == ERROR_NO_MORE_FILES;
-	}
 
-	while (!strcmp(findbuf.cFileName, ".") ||
-			!strcmp(findbuf.cFileName, ".."))
-		if (!FindNextFile(handle, &findbuf)) {
-			strbuf_release(&buf);
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf))
 			return GetLastError() == ERROR_NO_MORE_FILES;
-		}
 	FindClose(handle);
-	strbuf_release(&buf);
 	return 0;
 }
 
-#undef rmdir
 int mingw_rmdir(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
-	while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
-		if (!is_dir_empty(pathname)) {
+		if (!is_dir_empty(wpathname)) {
 			errno = ENOTEMPTY;
 			break;
 		}
@@ -276,14 +276,14 @@ int mingw_rmdir(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = rmdir(pathname);
+	       ret = _wrmdir(wpathname);
 	return ret;
 }
 
-static int make_hidden(const char *path)
+static int make_hidden(const wchar_t *path)
 {
-	DWORD attribs = GetFileAttributes(path);
-	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+	DWORD attribs = GetFileAttributesW(path);
+	if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
 		return 0;
 	errno = err_win_to_posix(GetLastError());
 	return -1;
@@ -291,19 +291,23 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
-	    make_hidden(dir))
-		warning("Failed to make '%s' hidden", dir);
+	wchar_t wdir[MAX_PATH];
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
+		if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
+			warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
 		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
 		 "dotGitOnly" : "true"));
 }
 
-#undef mkdir
 int mingw_mkdir(const char *path, int mode)
 {
-	int ret = mkdir(path);
+	int ret;
+	wchar_t wpath[MAX_PATH];
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
 	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
 		/*
 		 * In Windows a file or dir starting with a dot is not
@@ -312,17 +316,17 @@ int mingw_mkdir(const char *path, int mode)
 		 */
 		const char *start = basename((char*)path);
 		if (*start == '.')
-			return make_hidden(path);
+			return make_hidden(wpath);
 	}
 	return ret;
 }
 
-#undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
 	va_list args;
 	unsigned mode;
 	int fd;
+	wchar_t wfilename[MAX_PATH];
 
 	va_start(args, oflags);
 	mode = va_arg(args, int);
@@ -331,10 +335,12 @@ int mingw_open (const char *filename, int oflags, ...)
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
 
-	fd = open(filename, oflags, mode);
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	fd = _wopen(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
-		DWORD attrs = GetFileAttributes(filename);
+		DWORD attrs = GetFileAttributesW(wfilename);
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
@@ -346,7 +352,7 @@ int mingw_open (const char *filename, int oflags, ...)
 		 * such a file is created.
 		 */
 		const char *start = basename((char*)filename);
-		if (*start == '.' && make_hidden(filename))
+		if (*start == '.' && make_hidden(wfilename))
 			warning("Could not mark '%s' as hidden.", filename);
 	}
 	return fd;
@@ -369,38 +375,69 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 	return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
-#undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = fopen(filename, otype);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfopen(wfilename, wotype);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
-#undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = freopen(filename, otype, stream);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -426,10 +463,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
  */
 static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
-	int err;
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
-	if (!(err = get_file_attr(file_name, &fdata))) {
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
 		buf->st_ino = 0;
 		buf->st_gid = 0;
 		buf->st_uid = 0;
@@ -442,8 +481,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-			WIN32_FIND_DATAA findbuf;
-			HANDLE handle = FindFirstFileA(file_name, &findbuf);
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
 			if (handle != INVALID_HANDLE_VALUE) {
 				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
 						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
@@ -462,7 +501,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		}
 		return 0;
 	}
-	errno = err;
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	default:
+		errno = ENOENT;
+		break;
+	}
 	return -1;
 }
 
@@ -551,16 +606,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
 {
 	FILETIME mft, aft;
 	int fh, rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
 	/* must have write permission */
-	DWORD attrs = GetFileAttributes(file_name);
+	attrs = GetFileAttributesW(wfilename);
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors here; open() will report them */
-		SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
 	}
 
-	if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+	if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
 		rc = -1;
 		goto revert_attrs;
 	}
@@ -583,7 +642,7 @@ revert_attrs:
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors again */
-		SetFileAttributes(file_name, attrs);
+		SetFileAttributesW(wfilename, attrs);
 	}
 	return rc;
 }
@@ -594,6 +653,18 @@ unsigned int sleep (unsigned int seconds)
 	return 0;
 }
 
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
 int mkstemp(char *template)
 {
 	char *filename = mktemp(template);
@@ -652,17 +723,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
 	return result;
 }
 
-#undef getcwd
 char *mingw_getcwd(char *pointer, int len)
 {
 	int i;
-	char *ret = getcwd(pointer, len);
-	if (!ret)
-		return ret;
+	wchar_t wpointer[MAX_PATH];
+	if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+		return NULL;
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
 	for (i = 0; pointer[i]; i++)
 		if (pointer[i] == '\\')
 			pointer[i] = '/';
-	return ret;
+	return pointer;
 }
 
 #undef getenv
@@ -1495,33 +1567,36 @@ int mingw_rename(const char *pold, const char *pnew)
 {
 	DWORD attrs, gle;
 	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+		return -1;
 
 	/*
 	 * Try native rename() first to get errno right.
 	 * It is based on MoveFile(), which cannot overwrite existing files.
 	 */
-	if (!rename(pold, pnew))
+	if (!_wrename(wpold, wpnew))
 		return 0;
 	if (errno != EEXIST)
 		return -1;
 repeat:
-	if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 		return 0;
 	/* TODO: translate more errors */
 	gle = GetLastError();
 	if (gle == ERROR_ACCESS_DENIED &&
-	    (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
 		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
 			errno = EISDIR;
 			return -1;
 		}
 		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
-		    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
-			if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 				return 0;
 			gle = GetLastError();
 			/* revert file attributes on failure */
-			SetFileAttributes(pnew, attrs);
+			SetFileAttributesW(wpnew, attrs);
 		}
 	}
 	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
@@ -1731,11 +1806,16 @@ void mingw_open_html(const char *unixpath)
 
 int link(const char *oldpath, const char *newpath)
 {
-	typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+	typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
 	static T create_hard_link = NULL;
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
 	if (!create_hard_link) {
 		create_hard_link = (T) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+			GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
 		if (!create_hard_link)
 			create_hard_link = (T)-1;
 	}
@@ -1743,7 +1823,7 @@ int link(const char *oldpath, const char *newpath)
 		errno = ENOSYS;
 		return -1;
 	}
-	if (!create_hard_link(newpath, oldpath, NULL)) {
+	if (!create_hard_link(wnewpath, woldpath, NULL)) {
 		errno = err_win_to_posix(GetLastError());
 		return -1;
 	}
diff --git a/compat/mingw.h b/compat/mingw.h
index ddb228473b..ea8c1f8993 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -182,6 +182,19 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 

From bf738bc1c1988a849da8740621eade8cd271cab1 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:01:09 +0100
Subject: [PATCH 3302/3720] Win32: Unicode file name support (dirent)

Changes opendir/readdir to use Windows Unicode APIs and convert between
UTF-8/UTF-16.

Removes parameter checks that are already covered by xutftowcs_path. This
changes detection of ENAMETOOLONG from MAX_PATH - 2 to MAX_PATH (matching
is_dir_empty in mingw.c). If name + "/*" or the resulting absolute path is
too long, FindFirstFile fails and errno is set through err_win_to_posix.

Increases the size of dirent.d_name to accommodate the full
WIN32_FIND_DATA.cFileName converted to UTF-8 (UTF-16 to UTF-8 conversion
may grow by factor three in the worst case).

Signed-off-by: Karsten Blees 
---
 compat/win32/dirent.c | 30 ++++++++++--------------------
 compat/win32/dirent.h |  2 +-
 2 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 82a515c21b..52420ec7d4 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -6,10 +6,10 @@ struct DIR {
 	int dd_stat;          /* 0-based index */
 };
 
-static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
 {
-	/* copy file name from WIN32_FIND_DATA to dirent */
-	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+	/* convert UTF-16 name to UTF-8 */
+	xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
 
 	/* Set file type, based on WIN32_FIND_DATA */
 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -20,25 +20,15 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
 
 DIR *opendir(const char *name)
 {
-	char pattern[MAX_PATH];
-	WIN32_FIND_DATAA fdata;
+	wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
+	WIN32_FIND_DATAW fdata;
 	HANDLE h;
 	int len;
 	DIR *dir;
 
-	/* check that name is not NULL */
-	if (!name) {
-		errno = EINVAL;
+	/* convert name to UTF-16 and check length < MAX_PATH */
+	if ((len = xutftowcs_path(pattern, name)) < 0)
 		return NULL;
-	}
-	/* check that the pattern won't be too long for FindFirstFileA */
-	len = strlen(name);
-	if (len + 2 >= MAX_PATH) {
-		errno = ENAMETOOLONG;
-		return NULL;
-	}
-	/* copy name to temp buffer */
-	memcpy(pattern, name, len + 1);
 
 	/* append optional '/' and wildcard '*' */
 	if (len && !is_dir_sep(pattern[len - 1]))
@@ -47,7 +37,7 @@ DIR *opendir(const char *name)
 	pattern[len] = 0;
 
 	/* open find handle */
-	h = FindFirstFileA(pattern, &fdata);
+	h = FindFirstFileW(pattern, &fdata);
 	if (h == INVALID_HANDLE_VALUE) {
 		DWORD err = GetLastError();
 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
@@ -72,8 +62,8 @@ struct dirent *readdir(DIR *dir)
 	/* if first entry, dirent has already been set up by opendir */
 	if (dir->dd_stat) {
 		/* get next entry and convert from WIN32_FIND_DATA to dirent */
-		WIN32_FIND_DATAA fdata;
-		if (FindNextFileA(dir->dd_handle, &fdata)) {
+		WIN32_FIND_DATAW fdata;
+		if (FindNextFileW(dir->dd_handle, &fdata)) {
 			finddata2dirent(&dir->dd_dir, &fdata);
 		} else {
 			DWORD lasterr = GetLastError();
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 8838cd61fc..058207e4bf 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,7 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
-	char d_name[MAX_PATH];     /* file name */
+	char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
 };
 
 DIR *opendir(const char *dirname);

From ab403cf5ac994cb9a909b800813f3c827067834b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 4 Feb 2012 21:54:36 +0100
Subject: [PATCH 3303/3720] Unicode file name support (gitk and git-gui)

Assumes file names in git tree objects are UTF-8 encoded.

On most unix systems, the system encoding (and thus the TCL system
encoding) will be UTF-8, so file names will be displayed correctly.

On Windows, it is impossible to set the system encoding to UTF-8. Changing
the TCL system encoding (via 'encoding system ...', e.g. in the startup
code) is explicitly discouraged by the TCL docs.

Change gitk and git-gui functions dealing with file names to always convert
from and to UTF-8.

Signed-off-by: Karsten Blees 
---
 git-gui/git-gui.sh      | 11 +++++++----
 git-gui/lib/browser.tcl |  2 +-
 git-gui/lib/index.tcl   |  6 +++---
 gitk-git/gitk           | 16 ++++++++--------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index a59020bcc5..e5038ddd12 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -533,6 +533,9 @@ proc git {args} {
 
 	_trace_exec [concat $opt $cmdp $args]
 	set result [eval exec $opt $cmdp $args]
+	if {[encoding system] != "utf-8"} {
+		set result [encoding convertfrom utf-8 [encoding convertto $result]]
+	}
 	if {$::_trace} {
 		puts stderr "< $result"
 	}
@@ -1087,7 +1090,7 @@ git-version proc _parse_config {arr_name args} {
 				[list git_read config] \
 				$args \
 				[list --null --list]]
-			fconfigure $fd_rc -translation binary
+			fconfigure $fd_rc -translation binary -encoding utf-8
 			set buf [read $fd_rc]
 			close $fd_rc
 		}
@@ -1652,7 +1655,7 @@ proc read_diff_index {fd after} {
 		set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			[lindex $i 4]? \
 			[list [lindex $i 0] [lindex $i 2]] \
 			[list]
@@ -1685,7 +1688,7 @@ proc read_diff_files {fd after} {
 		set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			?[lindex $i 4] \
 			[list] \
 			[list [lindex $i 0] [lindex $i 2]]
@@ -1708,7 +1711,7 @@ proc read_ls_others {fd after} {
 	set pck [split $buf_rlo "\0"]
 	set buf_rlo [lindex $pck end]
 	foreach p [lrange $pck 0 end-1] {
-		set p [encoding convertfrom $p]
+		set p [encoding convertfrom utf-8 $p]
 		if {[string index $p end] eq {/}} {
 			set p [string range $p 0 end-1]
 		}
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 4fca8fb13c..555db896f4 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary
+	fconfigure $fd -blocking 0 -translation binary -encoding utf-8
 	fileevent $fd readable [cb _read $fd]
 }
 
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdde21..6ca0a6e369 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -115,7 +115,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
 		set info [lindex $s 2]
 		if {$info eq {}} continue
 
-		puts -nonewline $fd "$info\t[encoding convertto $path]\0"
+		puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -186,7 +186,7 @@ proc write_update_index {fd pathList totalCnt batch after} {
 		?M {set new M_}
 		?? {continue}
 		}
-		puts -nonewline $fd "[encoding convertto $path]\0"
+		puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -247,7 +247,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
 		?M -
 		?T -
 		?D {
-			puts -nonewline $fd "[encoding convertto $path]\0"
+			puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 			display_file $path ?_
 		}
 		}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 808ccc84d7..31a969c8e7 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7329,7 +7329,7 @@ proc gettreeline {gtf id} {
 	if {[string index $fname 0] eq "\""} {
 	    set fname [lindex $fname 0]
 	}
-	set fname [encoding convertfrom $fname]
+	set fname [encoding convertfrom utf-8 $fname]
 	lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -7551,7 +7551,7 @@ proc gettreediffline {gdtf ids} {
 	    if {[string index $file 0] eq "\""} {
 		set file [lindex $file 0]
 	    }
-	    set file [encoding convertfrom $file]
+	    set file [encoding convertfrom utf-8 $file]
 	    if {$file ne [lindex $treediff end]} {
 		lappend treediff $file
 		lappend sublist $file
@@ -7700,7 +7700,7 @@ proc makediffhdr {fname ids} {
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -7734,7 +7734,7 @@ proc getblobdiffline {bdf ids} {
 	}
 	if {![string compare -length 5 "diff " $line]} {
 	    if {![regexp {^diff (--cc|--git) } $line m type]} {
-		set line [encoding convertfrom $line]
+		set line [encoding convertfrom utf-8 $line]
 		$ctext insert end "$line\n" hunksep
 		continue
 	    }
@@ -7781,7 +7781,7 @@ proc getblobdiffline {bdf ids} {
 	    makediffhdr $fname $ids
 
 	} elseif {![string compare -length 16 "* Unmerged path " $line]} {
-	    set fname [encoding convertfrom [string range $line 16 end]]
+	    set fname [encoding convertfrom utf-8 [string range $line 16 end]]
 	    $ctext insert end "\n"
 	    set curdiffstart [$ctext index "end - 1c"]
 	    lappend ctext_file_names $fname
@@ -7836,7 +7836,7 @@ proc getblobdiffline {bdf ids} {
 		if {[string index $fname 0] eq "\""} {
 		    set fname [lindex $fname 0]
 		}
-		set fname [encoding convertfrom $fname]
+		set fname [encoding convertfrom utf-8 $fname]
 		set i [lsearch -exact $treediffs($ids) $fname]
 		if {$i >= 0} {
 		    setinlist difffilestart $i $curdiffstart
@@ -7855,7 +7855,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
-	    set line [encoding convertfrom $line]
+	    set line [encoding convertfrom utf-8 $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {
@@ -11520,7 +11520,7 @@ proc cache_gitattr {attr pathlist} {
 	    foreach row [split $rlist "\n"] {
 		if {[regexp "(.*): $attr: (.*)" $row m path value]} {
 		    if {[string index $path 0] eq "\""} {
-			set path [encoding convertfrom [lindex $path 0]]
+			set path [encoding convertfrom utf-8 [lindex $path 0]]
 		    }
 		    set path_attr_cache($attr,$path) $value
 		}

From 1285289526fd8e5bd35457144fdf0be425a69284 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:27:53 +0100
Subject: [PATCH 3304/3720] Win32: Unicode arguments (outgoing)

Convert command line arguments from UTF-8 to UTF-16 when creating other
processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 5d5f30bd2c..de0a55fe84 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -955,9 +955,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFO si;
+	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
 	struct strbuf envblk, args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
 	unsigned flags;
 	BOOL ret;
 
@@ -993,6 +994,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	si.hStdOutput = winansi_get_osfhandle(fhout);
 	si.hStdError = winansi_get_osfhandle(fherr);
 
+	if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
 	if (prepend_cmd) {
@@ -1010,6 +1016,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			free(quoted);
 	}
 
+	wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
@@ -1031,12 +1041,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	}
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir, &si, &pi);
+	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
 	if (env)
 		strbuf_release(&envblk);
-	strbuf_release(&args);
+	free(wargs);
 
 	if (!ret) {
 		errno = ENOENT;

From ba915ad59b00f8fa395e585b2d9ea77f854ecad2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:28:27 +0100
Subject: [PATCH 3305/3720] Win32: Unicode arguments (incoming)

Convert command line arguments from UTF-16 to UTF-8 on startup.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index de0a55fe84..428c056009 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2040,10 +2040,41 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
  */
 int _CRT_glob = 0;
 
+typedef struct {
+	int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+		_startupinfo *si);
+
 void mingw_startup()
 {
-	/* copy executable name to argv[0] */
-	__argv[0] = xstrdup(_pgmptr);
+	int i, len, maxlen, argc;
+	char *buffer;
+	wchar_t **wenv, **wargv;
+	_startupinfo si;
+
+	/* get wide char arguments and environment */
+	si.newmode = 0;
+	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(_wpgmptr);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = xmalloc(maxlen);
+
+	/* convert command line arguments and environment to UTF-8 */
+	len = xwcstoutf(buffer, _wpgmptr, maxlen);
+	__argv[0] = xmemdupz(buffer, len);
+	for (i = 1; i < argc; i++) {
+		len = xwcstoutf(buffer, wargv[i], maxlen);
+		__argv[i] = xmemdupz(buffer, len);
+	}
+	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);

From b67fc8d0bdd5b1566712af620558619b8d7194d2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:17:49 +0100
Subject: [PATCH 3306/3720] Win32: sync Unicode console output and file system

Use the same Unicode conversion functions for file names and console
conversions so that the file system and console output are in sync when
checking out legacy encoded repositories (i.e. with invalid UTF-8 file
names).

Signed-off-by: Karsten Blees 
---
 compat/winansi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a3e4d88295..9f95954390 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -120,8 +120,7 @@ static void write_console(unsigned char *str, size_t len)
 	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
 
 	/* convert utf-8 to utf-16 */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
-			ARRAY_SIZE(wbuf));
+	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);

From d9852214fa0a8ff920927e39c11e1551ba8ce933 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:07:46 +0100
Subject: [PATCH 3307/3720] Win32: Unicode environment (outgoing)

Convert environment from UTF-8 to UTF-16 when creating other processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 428c056009..d78ac239e0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -957,9 +957,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 {
 	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
-	struct strbuf envblk, args;
-	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
-	unsigned flags;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 
 	/* Determine whether or not we are associated to a console */
@@ -976,7 +976,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * instead of CREATE_NO_WINDOW to make ssh
 		 * recognize that it has no console.
 		 */
-		flags = DETACHED_PROCESS;
+		flags |= DETACHED_PROCESS;
 	} else {
 		/* There is already a console. If we specified
 		 * DETACHED_PROCESS here, too, Windows would
@@ -984,7 +984,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * The same is true for CREATE_NO_WINDOW.
 		 * Go figure!
 		 */
-		flags = 0;
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
@@ -1023,6 +1022,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
+		int size = 0, wenvsz = 0, wenvpos = 0;
 
 		for (e = env; *e; e++)
 			count++;
@@ -1032,20 +1032,22 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
 		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
 
-		strbuf_init(&envblk, 0);
+		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
-			strbuf_addstr(&envblk, *e);
-			strbuf_addch(&envblk, '\0');
+			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
 		}
+		/* add final \0 terminator */
+		wenvblk[wenvpos] = 0;
 		free(sorted_env);
 	}
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
+		wenvblk, dir ? wdir : NULL, &si, &pi);
 
-	if (env)
-		strbuf_release(&envblk);
+	free(wenvblk);
 	free(wargs);
 
 	if (!ret) {

From 0d37e9787a846af7f7159097e18ee9763673a95b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 25 Apr 2011 23:32:27 +0100
Subject: [PATCH 3308/3720] Win32: Unicode environment (incoming)

Convert environment from UTF-16 to UTF-8 on startup.

No changes to getenv() are necessary, as the MSVCRT version is implemented
on top of char **environ.

However, putenv / _wputenv from MSVCRT no longer work, for two reasons:
1. they try to keep environ, _wenviron and the Win32 process environment
in sync, using the default system encoding instead of UTF-8 to convert
between charsets
2. msysgit and MSVCRT use different allocators, memory allocated in git
cannot be freed by the CRT and vice versa

Implement mingw_putenv using the env_setenv helper function from the
environment merge code.

Note that in case of memory allocation failure, putenv now dies with error
message (due to xrealloc) instead of failing with ENOMEM. As git assumes
setenv / putenv to always succeed, this prevents it from continuing with
incorrect settings.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index d78ac239e0..fe1d0de81f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1282,6 +1282,12 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -2064,6 +2070,11 @@ void mingw_startup()
 	maxlen = wcslen(_wpgmptr);
 	for (i = 1; i < argc; i++)
 		maxlen = max(maxlen, wcslen(wargv[i]));
+	for (i = 0; wenv[i]; i++)
+		maxlen = max(maxlen, wcslen(wenv[i]));
+
+	/* nedmalloc can't free CRT memory, allocate resizable environment list */
+	environ = xcalloc(i + 1, sizeof(char*));
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2076,6 +2087,10 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wargv[i], maxlen);
 		__argv[i] = xmemdupz(buffer, len);
 	}
+	for (i = 0; wenv[i]; i++) {
+		len = xwcstoutf(buffer, wenv[i], maxlen);
+		environ[i] = xmemdupz(buffer, len);
+	}
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
diff --git a/compat/mingw.h b/compat/mingw.h
index ea8c1f8993..af1574c435 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -200,6 +200,8 @@ char *mingw_getcwd(char *pointer, int len);
 
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
+int mingw_putenv(const char *namevalue);
+#define putenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From b330b276c8453c1a0adc0b94ea20472497302c7b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 20 Aug 2011 14:27:02 +0200
Subject: [PATCH 3309/3720] MinGW: disable legacy encoding tests

On Windows, all native APIs are Unicode-based. It is impossible to pass
legacy encoded byte arrays to a process via command line or environment
variables. Disable the tests that try to do so.

In t3901, most tests still work if we don't mess up the repository encoding
in setup, so don't switch to ISO-8859-1 on MinGW.

Note that i18n tests that do their encoding tricks via encoded files (such
as t3900) are not affected by this.

Signed-off-by: Karsten Blees 
---
 t/t3901-i18n-patch.sh | 19 +++++++++++--------
 t/t4201-shortlog.sh   |  6 +++---
 t/t8005-blame-i18n.sh |  8 ++++----
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 31a5770b34..55c8a2f576 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -54,10 +54,13 @@ test_expect_success setup '
 	git add yours &&
 	git commit -s -m "Second on side" &&
 
-	# the second one on the side branch is ISO-8859-1
-	git config i18n.commitencoding ISO8859-1 &&
-	# use author and committer name in ISO-8859-1 to match it.
-	. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+	if test_have_prereq NOT_MINGW
+	then
+		# the second one on the side branch is ISO-8859-1
+		git config i18n.commitencoding ISO8859-1 &&
+		# use author and committer name in ISO-8859-1 to match it.
+		. "$TEST_DIRECTORY"/t3901-8859-1.txt
+	fi &&
 	test_tick &&
 	echo Yet another >theirs &&
 	git add theirs &&
@@ -119,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
 	check_encoding 2
 '
 
-test_expect_success 'rebase (L/L)' '
+test_expect_success NOT_MINGW 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
 	git config i18n.commitencoding ISO8859-1 &&
 	git config i18n.logoutputencoding ISO8859-1 &&
@@ -131,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 	check_encoding 2 8859
 '
 
-test_expect_success 'rebase (L/U)' '
+test_expect_success NOT_MINGW 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
 	git config i18n.commitencoding ISO8859-1 &&
@@ -159,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/L)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
 	git config i18n.commitencoding ISO8859-1 &&
@@ -189,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/U)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6872ba1a42..48963811bf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
 	test_cmp expect log.predictable
 '
 
-test_expect_success 'shortlog wrapping' '
+test_expect_success NOT_MINGW 'shortlog wrapping' '
 	cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
 	test_cmp expect out
 '
 
-test_expect_success 'shortlog from non-git directory' '
+test_expect_success NOT_MINGW 'shortlog from non-git directory' '
 	git log HEAD >log &&
 	GIT_DIR=non-existing git shortlog -w out &&
 	test_cmp expect out
@@ -135,7 +135,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success 'shortlog encoding' '
+test_expect_success NOT_MINGW 'shortlog encoding' '
 	git reset --hard "$commit" &&
 	git config --unset i18n.commitencoding &&
 	echo 2 > a1 &&
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index cb390559f9..a6e73d0635 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.commitencoding' '
 	git blame --incremental file | \
 		egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.logoutputencoding' '
 	git config i18n.logoutputencoding eucJP &&
 	git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=UTF-8' '
 	git blame --incremental --encoding=UTF-8 file | \
 		egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=none' '
 	git blame --incremental --encoding=none file | \
 		egrep "^(author|summary) " > actual &&

From 9ed6192d7b34e6bb58e04232b294bcb417d7e0ec Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:29:40 +0100
Subject: [PATCH 3310/3720] Win32: fix environment memory leaks

All functions that modify the environment have memory leaks.

Disable gitunsetenv in the Makefile and use env_setenv (via mingw_putenv)
instead (this frees removed environment entries).

Move xstrdup from env_setenv to make_augmented_environ, so that
mingw_putenv no longer copies the environment entries (according to POSIX
[1], "the string [...] shall become part of the environment"). This also
fixes the memory leak in gitsetenv, which expects a POSIX compliant putenv.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html

Note: This patch depends on taking control of char **environ and having
our own mingw_putenv (both introduced in "Win32: Unicode environment
(incoming)").

Signed-off-by: Karsten Blees 
---
 Makefile       |  2 --
 compat/mingw.c | 10 ++++++----
 compat/mingw.h |  1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index c82f297f0f..77111b1f46 100644
--- a/Makefile
+++ b/Makefile
@@ -1160,7 +1160,6 @@ ifeq ($(uname_S),Windows)
 	NO_IPV6 = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
@@ -1257,7 +1256,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SYMLINK_HEAD = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index fe1d0de81f..bbd35d8bd4 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1255,14 +1255,14 @@ static char **env_setenv(char **env, const char *name)
 			for (i = 0; env[i]; i++)
 				;
 			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 			env[i+1] = NULL;
 		}
 	}
 	else {
 		free(env[i]);
 		if (*eq)
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 		else
 			for (; env[i]; i++)
 				env[i] = env[i+1];
@@ -1277,8 +1277,10 @@ char **make_augmented_environ(const char *const *vars)
 {
 	char **env = copy_environ();
 
-	while (*vars)
-		env = env_setenv(env, *vars++);
+	while (*vars) {
+		const char *v = *vars++;
+		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+	}
 	return env;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index af1574c435..ba21474515 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -202,6 +202,7 @@ char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 int mingw_putenv(const char *namevalue);
 #define putenv mingw_putenv
+#define unsetenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 3841c80338b78b98fca8644d9fafbfa6130d63ee Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 23:42:09 +0100
Subject: [PATCH 3311/3720] Win32: unify environment case-sensitivity

The environment on Windows is case-insensitive. Some environment functions
(such as unsetenv and make_augmented_environ) have always used case-
sensitive comparisons instead, while others (getenv, putenv, sorting in
spawn*) were case-insensitive.

Prevent potential inconsistencies by using case-insensitive comparison in
lookup_env (used by putenv, unsetenv and make_augmented_environ).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bbd35d8bd4..bef2f3314e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1234,8 +1234,7 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 	int i;
 
 	for (i = 0; env[i]; i++) {
-		if (0 == strncmp(env[i], name, nmln)
-		    && '=' == env[i][nmln])
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
 			/* matches */
 			return i;
 	}

From a4bd7dc7391ebff0ad28c1761837f68fba5031e5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:33:17 +0100
Subject: [PATCH 3312/3720] Win32: simplify internal mingw_spawn* APIs

The only public spawn function that needs to tweak the environment is
mingw_spawnvpe (called from start_command). Nevertheless, all internal
spawn* functions take an env parameter and needlessly pass the global
char **environ around. Remove the env parameter where it's not needed.

This removes the internal mingw_execve abstraction, which is no longer
needed.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bef2f3314e..311a1832d0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1077,10 +1077,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-			   int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -1122,7 +1121,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 	return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
 	const char *interpr = parse_interpreter(cmd);
 	char **path;
@@ -1140,7 +1139,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 		argv2 = xmalloc(sizeof(*argv) * (argc+1));
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-		pid = mingw_spawnve(prog, argv2, env, 1);
+		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -1155,13 +1154,13 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 	return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+void mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
-	if (!try_shell_exec(cmd, argv, (char **)env)) {
+	if (!try_shell_exec(cmd, argv)) {
 		int pid, status;
 
-		pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
 			return;
 		if (waitpid(pid, &status, 0) < 0)
@@ -1176,7 +1175,7 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	char *prog = path_lookup(cmd, path, 0);
 
 	if (prog) {
-		mingw_execve(prog, argv, environ);
+		mingw_execv(prog, argv);
 		free(prog);
 	} else
 		errno = ENOENT;
@@ -1184,11 +1183,6 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	free_path_split(path);
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
-{
-	mingw_execve(cmd, argv, environ);
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
 	if (pid > 0 && sig == SIGTERM) {

From 1e79ae7007c8313fdfbd2cccd1936d6e2792210f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:05:04 +0100
Subject: [PATCH 3313/3720] Win32: move environment functions

Move environment helper functions up so that they can be reused by
mingw_getenv and mingw_spawnve_fd in subsequent patches.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 106 ++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 311a1832d0..0c406669df 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,6 +737,53 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
+static int env_compare(const void *a, const void *b)
+{
+	char *const *ea = a;
+	char *const *eb = b;
+	return strcasecmp(*ea, *eb);
+}
+
+static int lookup_env(char **env, const char *name, size_t nmln)
+{
+	int i;
+
+	for (i = 0; env[i]; i++) {
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
+			/* matches */
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * If name contains '=', then sets the variable, otherwise it unsets it
+ */
+static char **env_setenv(char **env, const char *name)
+{
+	char *eq = strchrnul(name, '=');
+	int i = lookup_env(env, name, eq-name);
+
+	if (i < 0) {
+		if (*eq) {
+			for (i = 0; env[i]; i++)
+				;
+			env = xrealloc(env, (i+2)*sizeof(*env));
+			env[i] = (char*) name;
+			env[i+1] = NULL;
+		}
+	}
+	else {
+		free(env[i]);
+		if (*eq)
+			env[i] = (char*) name;
+		else
+			for (; env[i]; i++)
+				env[i] = env[i+1];
+	}
+	return env;
+}
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -754,6 +801,12 @@ char *mingw_getenv(const char *name)
 	return result;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -936,13 +989,6 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
-static int env_compare(const void *a, const void *b)
-{
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
-}
-
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1223,46 +1269,6 @@ void free_environ(char **env)
 	free(env);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
-{
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
-	}
-	return -1;
-}
-
-/*
- * If name contains '=', then sets the variable, otherwise it unsets it
- */
-static char **env_setenv(char **env, const char *name)
-{
-	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
-
-	if (i < 0) {
-		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
-		}
-	}
-	else {
-		free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-	}
-	return env;
-}
-
 /*
  * Copies global environ and adjusts variables as specified by vars.
  */
@@ -1277,12 +1283,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-int mingw_putenv(const char *namevalue)
-{
-	environ = env_setenv(environ, namevalue);
-	return 0;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 79f40d6f21deb28fda48549d738283741723d770 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Wed, 5 Oct 2011 22:01:46 +0200
Subject: [PATCH 3314/3720] Win32: unify environment function names

Environment helper functions use random naming ('env' prefix or suffix or
both, with or without '_'). Change to POSIX naming scheme ('env' suffix,
no '_').

Env_setenv has more in common with putenv than setenv. Change to do_putenv.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0c406669df..e5d8c6a438 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,14 +737,14 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int env_compare(const void *a, const void *b)
+static int compareenv(const void *a, const void *b)
 {
 	char *const *ea = a;
 	char *const *eb = b;
 	return strcasecmp(*ea, *eb);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
+static int lookupenv(char **env, const char *name, size_t nmln)
 {
 	int i;
 
@@ -759,10 +759,10 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **env_setenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name)
 {
 	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
+	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
@@ -803,7 +803,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = env_setenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue);
 	return 0;
 }
 
@@ -1076,7 +1076,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		/* environment must be sorted */
 		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
 
 		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
@@ -1278,7 +1278,7 @@ char **make_augmented_environ(const char *const *vars)
 
 	while (*vars) {
 		const char *v = *vars++;
-		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
 	}
 	return env;
 }

From 4999c7731dca9528d666df2497a2b9698087b77f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:31:57 +0100
Subject: [PATCH 3315/3720] Win32: factor out environment block creation

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 55 +++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e5d8c6a438..be381573f1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -989,6 +989,36 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
+/*
+ * Create environment block suitable for CreateProcess.
+ */
+static wchar_t *make_environment_block(char **env)
+{
+	wchar_t *wenvblk = NULL;
+	int count = 0;
+	char **e, **tmpenv;
+	int size = 0, wenvsz = 0, wenvpos = 0;
+
+	for (e = env; *e; e++)
+		count++;
+
+	/* environment must be sorted */
+	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+
+	/* create environment block from temporary environment */
+	for (e = tmpenv; *e; e++) {
+		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+	}
+	/* add final \0 terminator */
+	wenvblk[wenvpos] = 0;
+	free(tmpenv);
+	return wenvblk;
+}
+
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1065,29 +1095,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env) {
-		int count = 0;
-		char **e, **sorted_env;
-		int size = 0, wenvsz = 0, wenvpos = 0;
-
-		for (e = env; *e; e++)
-			count++;
-
-		/* environment must be sorted */
-		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
-		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
-
-		/* create environment block from temporary environment */
-		for (e = sorted_env; *e; e++) {
-			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
-			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
-		}
-		/* add final \0 terminator */
-		wenvblk[wenvpos] = 0;
-		free(sorted_env);
-	}
+	if (env)
+		wenvblk = make_environment_block(env);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,

From 0659189110f7eeb25e1d4360df8c9cdd818a4ca4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:57:14 +0100
Subject: [PATCH 3316/3720] Win32: don't copy the environment twice when
 spawning child processes

When spawning child processes via start_command(), the environment and all
environment entries are copied twice. First by make_augmented_environ /
copy_environ to merge with child_process.env. Then a second time by
make_environment_block to create a sorted environment block string as
required by CreateProcess.

Move the merge logic to make_environment_block so that we only need to copy
the environment once. This changes semantics of the env parameter: it now
expects a delta (such as child_process.env) rather than a full environment.
This is not a problem as the parameter is only used by start_command()
(all other callers previously passed char **environ, and now pass NULL).

The merge logic no longer xstrdup()s the environment strings, so do_putenv
must not free them. Add a parameter to distinguish this from normal putenv.

Remove the now unused make_augmented_environ / free_environ API.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 74 ++++++++++++++++----------------------------------
 compat/mingw.h |  6 ----
 run-command.c  | 10 ++-----
 3 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index be381573f1..9a0b39a47e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -759,7 +759,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **do_putenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
@@ -774,7 +774,8 @@ static char **do_putenv(char **env, const char *name)
 		}
 	}
 	else {
-		free(env[i]);
+		if (free_old)
+			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
 		else
@@ -803,7 +804,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue, 1);
 	return 0;
 }
 
@@ -990,21 +991,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 }
 
 /*
- * Create environment block suitable for CreateProcess.
+ * Create environment block suitable for CreateProcess. Merges current
+ * process environment and the supplied environment changes.
  */
-static wchar_t *make_environment_block(char **env)
+static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
 	int count = 0;
 	char **e, **tmpenv;
 	int size = 0, wenvsz = 0, wenvpos = 0;
 
-	for (e = env; *e; e++)
+	while (environ[count])
 		count++;
 
-	/* environment must be sorted */
+	/* copy the environment */
 	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+
+	/* merge supplied environment changes into the temporary environment */
+	for (e = deltaenv; e && *e; e++)
+		tmpenv = do_putenv(tmpenv, *e, 0);
+
+	/* environment must be sorted */
+	for (count = 0; tmpenv[count]; )
+		count++;
 	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
 
 	/* create environment block from temporary environment */
@@ -1027,7 +1037,7 @@ struct pinfo_t {
 struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
-static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
@@ -1095,8 +1105,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env)
-		wenvblk = make_environment_block(env);
+	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1134,10 +1143,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
 static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 		     const char *dir,
 		     int fhin, int fhout, int fherr)
 {
@@ -1161,14 +1170,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 				pid = -1;
 			}
 			else {
-				pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
 						       fhin, fhout, fherr);
 				free(iprog);
 			}
 			argv[0] = argv0;
 		}
 		else
-			pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
 					       fhin, fhout, fherr);
 		free(prog);
 	}
@@ -1257,41 +1266,6 @@ int mingw_kill(pid_t pid, int sig)
 	return -1;
 }
 
-static char **copy_environ(void)
-{
-	char **env;
-	int i = 0;
-	while (environ[i])
-		i++;
-	env = xmalloc((i+1)*sizeof(*env));
-	for (i = 0; environ[i]; i++)
-		env[i] = xstrdup(environ[i]);
-	env[i] = NULL;
-	return env;
-}
-
-void free_environ(char **env)
-{
-	int i;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-/*
- * Copies global environ and adjusts variables as specified by vars.
- */
-char **make_augmented_environ(const char *const *vars)
-{
-	char **env = copy_environ();
-
-	while (*vars) {
-		const char *v = *vars++;
-		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
-	}
-	return env;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
diff --git a/compat/mingw.h b/compat/mingw.h
index ba21474515..04b6523255 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -335,12 +335,6 @@ void mingw_open_html(const char *path);
 void mingw_mark_as_git_dir(const char *dir);
 #define mark_as_git_dir mingw_mark_as_git_dir
 
-/*
- * helpers
- */
-
-char **make_augmented_environ(const char *const *vars);
-void free_environ(char **env);
 
 /**
  * Converts UTF-8 encoded string to UTF-16LE.
diff --git a/run-command.c b/run-command.c
index 1db8abf984..6d0dc3da91 100644
--- a/run-command.c
+++ b/run-command.c
@@ -381,7 +381,6 @@ fail_pipe:
 {
 	int fhin = 0, fhout = 1, fherr = 2;
 	const char **sargv = cmd->argv;
-	char **env = environ;
 
 	if (cmd->no_stdin)
 		fhin = open("/dev/null", O_RDWR);
@@ -406,25 +405,20 @@ fail_pipe:
 	else if (cmd->out > 1)
 		fhout = dup(cmd->out);
 
-	if (cmd->env)
-		env = make_augmented_environ(cmd->env);
-
 	if (cmd->git_cmd) {
 		cmd->argv = prepare_git_cmd(cmd->argv);
 	} else if (cmd->use_shell) {
 		cmd->argv = prepare_shell_cmd(cmd->argv);
 	}
 
-	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
-				  fhin, fhout, fherr);
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
 	failed_errno = errno;
 	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 		error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 	if (cmd->clean_on_exit && cmd->pid >= 0)
 		mark_child_for_cleanup(cmd->pid);
 
-	if (cmd->env)
-		free_environ(env);
 	if (cmd->git_cmd)
 		free(cmd->argv);
 

From 81dd4fd2b6ceaea3c927ea7611596314d937de93 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:00:35 +0100
Subject: [PATCH 3317/3720] Win32: reduce environment array reallocations

Move environment array reallocation from do_putenv to the respective
callers. Keep track of the environment size in a global variable. Use
ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a
sufficiently sized environment array in make_environment_block to prevent
reallocations.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 60 ++++++++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9a0b39a47e..2d984bd8d3 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -758,19 +758,19 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
+ * Size includes the terminating NULL. Env must have room for size + 1 entries
+ * (in case of insert). Returns the new size. Optionally frees removed entries.
  */
-static char **do_putenv(char **env, const char *name, int free_old)
+static int do_putenv(char **env, const char *name, int size, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
+			env[size - 1] = (char*) name;
+			env[size] = NULL;
+			size++;
 		}
 	}
 	else {
@@ -778,13 +778,20 @@ static char **do_putenv(char **env, const char *name, int free_old)
 			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
-		else
+		else {
 			for (; env[i]; i++)
 				env[i] = env[i+1];
+			size--;
+		}
 	}
-	return env;
+	return size;
 }
 
+/* used number of elements of environ array, including terminating NULL */
+static int environ_size = 0;
+/* allocated size of environ array, in bytes */
+static int environ_alloc = 0;
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -804,7 +811,8 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue, 1);
+	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
+	environ_size = do_putenv(environ, namevalue, environ_size, 1);
 	return 0;
 }
 
@@ -997,31 +1005,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
-	int count = 0;
-	char **e, **tmpenv;
-	int size = 0, wenvsz = 0, wenvpos = 0;
+	char **tmpenv;
+	int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
 
-	while (environ[count])
-		count++;
+	while (deltaenv && deltaenv[i])
+		i++;
 
-	/* copy the environment */
-	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+	/* copy the environment, leaving space for changes */
+	tmpenv = xmalloc((size + i) * sizeof(char*));
+	memcpy(tmpenv, environ, size * sizeof(char*));
 
 	/* merge supplied environment changes into the temporary environment */
-	for (e = deltaenv; e && *e; e++)
-		tmpenv = do_putenv(tmpenv, *e, 0);
+	for (i = 0; deltaenv && deltaenv[i]; i++)
+		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
 	/* environment must be sorted */
-	for (count = 0; tmpenv[count]; )
-		count++;
-	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
 
 	/* create environment block from temporary environment */
-	for (e = tmpenv; *e; e++) {
-		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+	for (i = 0; tmpenv[i]; i++) {
+		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
 		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+		wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
 	}
 	/* add final \0 terminator */
 	wenvblk[wenvpos] = 0;
@@ -2052,7 +2057,9 @@ void mingw_startup()
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
 	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = xcalloc(i + 1, sizeof(char*));
+	environ = NULL;
+	environ_size = i + 1;
+	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2069,6 +2076,7 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wenv[i], maxlen);
 		environ[i] = xmemdupz(buffer, len);
 	}
+	environ[i] = NULL;
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */

From f84912d2e39d37f199f4a25a535ae246d88ec85d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:29:04 +0100
Subject: [PATCH 3318/3720] Win32: use low-level memory allocation during
 initialization

As of d41489a6 "Add more large blob test cases", git's high-level memory
allocation functions (xmalloc, xmemdupz etc.) access the environment to
simulate limited memory in tests (see 'getenv("GIT_ALLOC_LIMIT")' in
memory_limit_check()). These functions should not be used before the
environment is fully initialized (particularly not to initialize the
environment itself).

The current solution ('environ = NULL; ALLOC_GROW(environ...)') only works
because MSVCRT's getenv() reinitializes environ when it is NULL (i.e. it
leaves us with two sets of unusabe (non-UTF-8) and unfreeable (CRT-
allocated) environments).

Add our own set of malloc-or-die functions to be used in startup code.

Also check the result of __wgetmainargs, which may fail if there's not
enough memory for wide-char arguments and environment.

This patch is in preparation of the sorted environment feature, which
completely replaces MSVCRT's getenv() implementation.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 52 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2d984bd8d3..f6934f7b79 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2038,16 +2038,37 @@ typedef struct {
 extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
 		_startupinfo *si);
 
+static NORETURN void die_startup()
+{
+	fputs("fatal: not enough memory for initialization", stderr);
+	exit(128);
+}
+
+static void *malloc_startup(size_t size)
+{
+	void *result = malloc(size);
+	if (!result)
+		die_startup();
+	return result;
+}
+
+static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
+{
+	len = xwcstoutf(buffer, wcs, len) + 1;
+	return memcpy(malloc_startup(len), buffer, len);
+}
+
 void mingw_startup()
 {
-	int i, len, maxlen, argc;
+	int i, maxlen, argc;
 	char *buffer;
 	wchar_t **wenv, **wargv;
 	_startupinfo si;
 
 	/* get wide char arguments and environment */
 	si.newmode = 0;
-	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+	if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
+		die_startup();
 
 	/* determine size of argv and environ conversion buffer */
 	maxlen = wcslen(_wpgmptr);
@@ -2056,26 +2077,25 @@ void mingw_startup()
 	for (i = 0; wenv[i]; i++)
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
-	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = NULL;
+	/*
+	 * nedmalloc can't free CRT memory, allocate resizable environment
+	 * list. Note that xmalloc / xmemdupz etc. call getenv, so we cannot
+	 * use it while initializing the environment itself.
+	 */
 	environ_size = i + 1;
-	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
+	environ_alloc = alloc_nr(environ_size * sizeof(char*));
+	environ = malloc_startup(environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
-	buffer = xmalloc(maxlen);
+	buffer = malloc_startup(maxlen);
 
 	/* convert command line arguments and environment to UTF-8 */
-	len = xwcstoutf(buffer, _wpgmptr, maxlen);
-	__argv[0] = xmemdupz(buffer, len);
-	for (i = 1; i < argc; i++) {
-		len = xwcstoutf(buffer, wargv[i], maxlen);
-		__argv[i] = xmemdupz(buffer, len);
-	}
-	for (i = 0; wenv[i]; i++) {
-		len = xwcstoutf(buffer, wenv[i], maxlen);
-		environ[i] = xmemdupz(buffer, len);
-	}
+	__argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
+	for (i = 1; i < argc; i++)
+		__argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+	for (i = 0; wenv[i]; i++)
+		environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen);
 	environ[i] = NULL;
 	free(buffer);
 

From b6c976d8da991d16ba31d3b0d9eda10c4ae475a9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:30:02 +0100
Subject: [PATCH 3319/3720] Win32: keep the environment sorted

The Windows environment is sorted, keep it that way for O(log n)
environment access.

Change compareenv to compare only the keys, so that it can be used to
find an entry irrespective of the value.

Change lookupenv to binary seach for an entry. Return one's complement of
the insert position if not found (libc's bsearch returns NULL).

Replace MSVCRT's getenv with a minimal do_getenv based on the binary search
function.

Change do_putenv to insert new entries at the correct position. Simplify
the function by swapping if conditions and using memmove instead of for
loops.

Move qsort from make_environment_block to mingw_startup. We still need to
sort on startup to make sure that the environment is sorted according to
our compareenv function (while Win32 / CreateProcess requires the
environment block to be sorted case-insensitively, CreateProcess currently
doesn't enforce this, and some applications such as bash just don't care).

Note that environment functions are _not_ thread-safe and are not required
to be so by POSIX, the application is responsible for synchronizing access
to the environment. MSVCRT's getenv and our new getenv implementation are
better than that in that they are thread-safe with respect to other getenv
calls as long as the environment is not modified. Git's indiscriminate use
of getenv in background threads currently requires this property.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 98 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 62 insertions(+), 36 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f6934f7b79..67c9e9c4f6 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,23 +737,42 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int compareenv(const void *a, const void *b)
+/*
+ * Compare environment entries by key (i.e. stopping at '=' or '\0').
+ */
+static int compareenv(const void *v1, const void *v2)
 {
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
+	const char *e1 = *(const char**)v1;
+	const char *e2 = *(const char**)v2;
+
+	for (;;) {
+		int c1 = *e1++;
+		int c2 = *e2++;
+		c1 = (c1 == '=') ? 0 : tolower(c1);
+		c2 = (c2 == '=') ? 0 : tolower(c2);
+		if (c1 > c2)
+			return 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 == 0)
+			return 0;
+	}
 }
 
-static int lookupenv(char **env, const char *name, size_t nmln)
+static int bsearchenv(char **env, const char *name, size_t size)
 {
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
+	unsigned low = 0, high = size;
+	while (low < high) {
+		unsigned mid = low + ((high - low) >> 1);
+		int cmp = compareenv(&env[mid], &name);
+		if (cmp < 0)
+			low = mid + 1;
+		else if (cmp > 0)
+			high = mid;
+		else
+			return mid;
 	}
-	return -1;
+	return ~low; /* not found, return 1's complement of insert position */
 }
 
 /*
@@ -763,26 +782,24 @@ static int lookupenv(char **env, const char *name, size_t nmln)
  */
 static int do_putenv(char **env, const char *name, int size, int free_old)
 {
-	char *eq = strchrnul(name, '=');
-	int i = lookupenv(env, name, eq-name);
+	int i = bsearchenv(env, name, size - 1);
 
-	if (i < 0) {
-		if (*eq) {
-			env[size - 1] = (char*) name;
-			env[size] = NULL;
+	/* optionally free removed / replaced entry */
+	if (i >= 0 && free_old)
+		free(env[i]);
+
+	if (strchr(name, '=')) {
+		/* if new value ('key=value') is specified, insert or replace entry */
+		if (i < 0) {
+			i = ~i;
+			memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
 			size++;
 		}
-	}
-	else {
-		if (free_old)
-			free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else {
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-			size--;
-		}
+		env[i] = (char*) name;
+	} else if (i >= 0) {
+		/* otherwise ('key') remove existing entry */
+		size--;
+		memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
 	}
 	return size;
 }
@@ -792,15 +809,24 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-#undef getenv
+static char *do_getenv(const char *name)
+{
+	char *value;
+	int pos = bsearchenv(environ, name, environ_size - 1);
+	if (pos < 0)
+		return NULL;
+	value = strchr(environ[pos], '=');
+	return value ? &value[1] : NULL;
+}
+
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv(name);
+	char *result = do_getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
+		result = do_getenv("TMP");
 		if (!result)
-			result = getenv("TEMP");
+			result = do_getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */
@@ -1019,9 +1045,6 @@ static wchar_t *make_environment_block(char **deltaenv)
 	for (i = 0; deltaenv && deltaenv[i]; i++)
 		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
-	/* environment must be sorted */
-	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
-
 	/* create environment block from temporary environment */
 	for (i = 0; tmpenv[i]; i++) {
 		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
@@ -2099,6 +2122,9 @@ void mingw_startup()
 	environ[i] = NULL;
 	free(buffer);
 
+	/* sort environment for O(log n) getenv / putenv */
+	qsort(environ, i, sizeof(char*), compareenv);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 69baa621a32a8da06565ca40917fff80d4a50d97 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:35:26 +0100
Subject: [PATCH 3320/3720] Win32: patch Windows environment on startup

Fix Windows specific environment settings on startup rather than checking
for special values on every getenv call.

As a side effect, this makes the patched environment (i.e. with properly
initialized TMPDIR and TERM) available to child processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 67c9e9c4f6..36899908ee 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -809,7 +809,7 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-static char *do_getenv(const char *name)
+char *mingw_getenv(const char *name)
 {
 	char *value;
 	int pos = bsearchenv(environ, name, environ_size - 1);
@@ -819,22 +819,6 @@ static char *do_getenv(const char *name)
 	return value ? &value[1] : NULL;
 }
 
-char *mingw_getenv(const char *name)
-{
-	char *result = do_getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = do_getenv("TMP");
-		if (!result)
-			result = do_getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 int mingw_putenv(const char *namevalue)
 {
 	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
@@ -2125,6 +2109,21 @@ void mingw_startup()
 	/* sort environment for O(log n) getenv / putenv */
 	qsort(environ, i, sizeof(char*), compareenv);
 
+	/* fix Windows specific environment settings */
+
+	/* on Windows it is TMP and TEMP */
+	if (!getenv("TMPDIR")) {
+		const char *tmp = getenv("TMP");
+		if (!tmp)
+			tmp = getenv("TEMP");
+		if (tmp)
+			setenv("TMPDIR", tmp, 1);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "winansi", 1);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From cf4dc80323c77e2eac77f5a50c6378b7a59b6817 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:37:26 +0100
Subject: [PATCH 3321/3720] Win32: fix detection of empty directories in
 is_dir_empty

On Windows XP (not Win7), directories cannot be deleted while a find handle
is open, causing "Deletion of directory '...' failed. Should I try again?"
prompts.

Prior to 19d1e75d "Win32: Unicode file name support (except dirent)",
these failures were silently ignored due to strbuf_free in is_dir_empty
resetting GetLastError to ERROR_SUCCESS.

Close the find handle in is_dir_empty so that git doesn't block deletion
of the directory even after all other applications have released it.

Reported-by: John Chen 
Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 36899908ee..e6f331a581 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -243,8 +243,11 @@ static int is_dir_empty(const wchar_t *wpath)
 
 	while (!wcscmp(findbuf.cFileName, L".") ||
 			!wcscmp(findbuf.cFileName, L".."))
-		if (!FindNextFileW(handle, &findbuf))
-			return GetLastError() == ERROR_NO_MORE_FILES;
+		if (!FindNextFileW(handle, &findbuf)) {
+			DWORD err = GetLastError();
+			FindClose(handle);
+			return err == ERROR_NO_MORE_FILES;
+		}
 	FindClose(handle);
 	return 0;
 }

From a70d30085cd69ca7f93b5d6b57cf74f8b3c0b58b Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Fri, 23 Mar 2012 10:58:37 +0100
Subject: [PATCH 3322/3720] am: Use cat instead of echo to avoid DOS
 line-endings (fixes t4150)

Along the lines of 05d0e3b and f33946d, use cat instead of echo to avoid
line ending mismatches in the test result of "am empty-file does not
infloop" which make the test fail.

Signed-off-by: Sebastian Schuberth 
---
 git-am.sh | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/git-am.sh b/git-am.sh
index ef7191e562..a499e147b0 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -176,7 +176,9 @@ It does not apply to blobs recorded in its index.")"
 }
 
 clean_abort () {
-	test $# = 0 || echo >&2 "$@"
+	test $# = 0 || cat >&2 <
Date: Sun, 24 Jul 2011 15:54:04 +0200
Subject: [PATCH 3323/3720] t9350: point out that refs are not updated
 correctly

This happens only when the corresponding commits are not exported in
the current fast-export run. This can happen either when the relevant
commit is already marked, or when the commit is explicitly marked
as UNINTERESTING with a negative ref by another argument.

This breaks fast-export basec remote helpers.

Signed-off-by: Sverre Rabbelier 
---
 t/t9350-fast-export.sh | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 950d0ff498..74914dcc9a 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -440,4 +440,15 @@ test_expect_success 'fast-export quotes pathnames' '
 	)
 '
 
+cat > expected << EOF
+reset refs/heads/master
+from $(git rev-parse master)
+
+EOF
+
+test_expect_failure 'refs are updated even if no commits need to be exported' '
+	git fast-export master..master > actual &&
+	test_cmp expected actual
+'
+
 test_done

From 9c827d1221fa42ce80fb4a5f17e9c02461347324 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 15:55:26 +0200
Subject: [PATCH 3324/3720] fast-export: do not refer to non-existing marks

When calling `git fast-export a..a b` when a and b refer to the same
commit, nothing would be exported, and an incorrect reset line would
be printed for b ('from :0').

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 19509ea754..b0891b3735 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -529,9 +529,20 @@ static void get_tags_and_duplicates(struct object_array *pending,
 	}
 }
 
+static void handle_reset(const char *name, struct object *object)
+{
+	int mark = get_object_mark(object);
+
+	if (mark)
+		printf("reset %s\nfrom :%d\n\n", name,
+		       get_object_mark(object));
+	else
+		printf("reset %s\nfrom %s\n\n", name,
+		       sha1_to_hex(object->sha1));
+}
+
 static void handle_tags_and_duplicates(struct string_list *extra_refs)
 {
-	struct commit *commit;
 	int i;
 
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
@@ -543,9 +554,7 @@ static void handle_tags_and_duplicates(struct string_list *extra_refs)
 			break;
 		case OBJ_COMMIT:
 			/* create refs pointing to already seen commits */
-			commit = (struct commit *)object;
-			printf("reset %s\nfrom :%d\n\n", name,
-			       get_object_mark(&commit->object));
+			handle_reset(name, object);
 			show_progress();
 			break;
 		}

From 855476c1bc04c06a71e4bced401dac51be4e5cce Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 17:14:47 +0200
Subject: [PATCH 3325/3720] setup_revisions: remember whether a ref was
 positive or not

This will be required by fast-export, when no commits were
exported, but the refs should be set, of course.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 object.h   |  2 +-
 revision.c | 12 +++++++-----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/object.h b/object.h
index b6618d92bf..a28cd45c7c 100644
--- a/object.h
+++ b/object.h
@@ -12,7 +12,7 @@ struct object_array {
 	struct object_array_entry {
 		struct object *item;
 		const char *name;
-		unsigned mode;
+		unsigned mode, flags;
 	} *objects;
 };
 
diff --git a/revision.c b/revision.c
index b3554ed11b..3cdd0a358d 100644
--- a/revision.c
+++ b/revision.c
@@ -185,7 +185,7 @@ void mark_parents_uninteresting(struct commit *commit)
 	}
 }
 
-static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
+static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode, unsigned flags)
 {
 	if (!obj)
 		return;
@@ -206,11 +206,12 @@ static void add_pending_object_with_mode(struct rev_info *revs, struct object *o
 			return;
 	}
 	add_object_array_with_mode(obj, name, &revs->pending, mode);
+	revs->pending.objects[revs->pending.nr-1].flags = flags;
 }
 
 void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
 {
-	add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
+	add_pending_object_with_mode(revs, obj, name, S_IFINVALID, 0);
 }
 
 void add_head_to_pending(struct rev_info *revs)
@@ -1176,7 +1177,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
 					REV_CMD_LEFT, a_flags);
 			add_rev_cmdline(revs, &b->object, next,
 					REV_CMD_RIGHT, flags);
-			add_pending_object(revs, &a->object, this);
+			add_pending_object_with_mode(revs, &a->object, this,
+						     S_IFINVALID, flags_exclude);
 			add_pending_object(revs, &b->object, next);
 			return 0;
 		}
@@ -1207,7 +1209,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
 		verify_non_filename(revs->prefix, arg);
 	object = get_reference(revs, arg, sha1, flags ^ local_flags);
 	add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
-	add_pending_object_with_mode(revs, object, arg, mode);
+	add_pending_object_with_mode(revs, object, arg, mode, local_flags);
 	return 0;
 }
 
@@ -1820,7 +1822,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 		if (get_sha1_with_mode(revs->def, sha1, &mode))
 			die("bad default revision '%s'", revs->def);
 		object = get_reference(revs, revs->def, sha1, 0);
-		add_pending_object_with_mode(revs, object, revs->def, mode);
+		add_pending_object_with_mode(revs, object, revs->def, mode, 0);
 	}
 
 	/* Did the user ask for any diff output? Run the diff! */

From 2c8455e23ceb61ebeb2f4eea11ac38ba2c983655 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 15:40:23 +0200
Subject: [PATCH 3326/3720] fast-export: do not export negative refs

When calling `git fast-export master..next` we want to export
refs/heads/next, but not refs/heads/master.

Currently this is not a problem, because negative refs' commits
are never shown. In the next commit this will be changed in order
to make sure that 'master..master' does export master. I.e. even
refs whose commits are not shown are exported.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index b0891b3735..0dc5124675 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -484,7 +484,7 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		struct commit *commit = commit;
 		char *full_name;
 
-		if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
+		if ((e->flags & UNINTERESTING) || dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
 			continue;
 
 		switch (e->item->type) {

From 5804c25bd34844c227ed68060d4bc1bfb72f1b76 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 17:14:47 +0200
Subject: [PATCH 3327/3720] setup_revisions: remember whether a ref was
 positive or not

This will be required by fast-export, when no commits were
exported, but the refs should be set, of course.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c  | 36 +++++++++++++++++++++++++++++++-----
 t/t9350-fast-export.sh |  2 +-
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 0dc5124675..137792d49d 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -18,6 +18,8 @@
 #include "parse-options.h"
 #include "quote.h"
 
+#define REF_HANDLED (ALL_REV_FLAGS + 1)
+
 static const char *fast_export_usage[] = {
 	"git fast-export [rev-list-opts]",
 	NULL
@@ -473,6 +475,7 @@ static void handle_tag(const char *name, struct tag *tag)
 }
 
 static void get_tags_and_duplicates(struct object_array *pending,
+				    struct string_list *refs,
 				    struct string_list *extra_refs)
 {
 	struct tag *tag;
@@ -524,8 +527,11 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		if (commit->util)
 			/* more than one name for the same object */
 			string_list_append(extra_refs, full_name)->util = commit;
-		else
+		else {
 			commit->util = full_name;
+			/* we might need to set this ref explicitly */
+			string_list_append(refs, full_name)->util = commit;
+		}
 	}
 }
 
@@ -541,10 +547,29 @@ static void handle_reset(const char *name, struct object *object)
 		       sha1_to_hex(object->sha1));
 }
 
-static void handle_tags_and_duplicates(struct string_list *extra_refs)
+static void handle_tags_and_duplicates(struct string_list *refs, struct string_list *extra_refs)
 {
 	int i;
 
+	/* even if no commits were exported, we need to export the ref */
+	for (i = refs->nr - 1; i >= 0; i--) {
+		const char *name = refs->items[i].string;
+		struct object *object = refs->items[i].util;
+
+		if (!(object->flags & REF_HANDLED)) {
+			if (object->type & OBJ_TAG)
+				handle_tag(name, (struct tag *)object);
+			else {
+				if (!prefixcmp(name, "refs/tags/") &&
+				    (tag_of_filtered_mode != REWRITE ||
+				     !get_object_mark(object)))
+					continue;
+				handle_reset(name, object);
+				object->flags |= REF_HANDLED;
+			}
+		}
+	}
+
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
 		const char *name = extra_refs->items[i].string;
 		struct object *object = extra_refs->items[i].util;
@@ -634,7 +659,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info revs;
 	struct object_array commits = OBJECT_ARRAY_INIT;
-	struct string_list extra_refs = STRING_LIST_INIT_NODUP;
+	struct string_list refs = STRING_LIST_INIT_NODUP, extra_refs = STRING_LIST_INIT_NODUP;
 	struct commit *commit;
 	char *export_filename = NULL, *import_filename = NULL;
 	struct option options[] = {
@@ -684,7 +709,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 	if (import_filename && revs.prune_data.nr)
 		full_tree = 1;
 
-	get_tags_and_duplicates(&revs.pending, &extra_refs);
+	get_tags_and_duplicates(&revs.pending, &refs, &extra_refs);
 
 	if (prepare_revision_walk(&revs))
 		die("revision walk setup failed");
@@ -696,11 +721,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 		}
 		else {
 			handle_commit(commit, &revs);
+			commit->object.flags |= REF_HANDLED;
 			handle_tail(&commits, &revs);
 		}
 	}
 
-	handle_tags_and_duplicates(&extra_refs);
+	handle_tags_and_duplicates(&refs, &extra_refs);
 
 	if (export_filename)
 		export_marks(export_filename);
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 74914dcc9a..ea7dc21b9d 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -446,7 +446,7 @@ from $(git rev-parse master)
 
 EOF
 
-test_expect_failure 'refs are updated even if no commits need to be exported' '
+test_expect_success 'refs are updated even if no commits need to be exported' '
 	git fast-export master..master > actual &&
 	test_cmp expected actual
 '

From 5cf32455042841da3661b9be62db93531a204543 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Fri, 15 Jul 2011 16:37:28 +0200
Subject: [PATCH 3328/3720] t5800: test pushing a new branch with old content

This works now that fast-export has been fixed to properly handle
refs that point to a commit that was not exported during the current
fast-export run.
---
 t/t5800-remote-helpers.sh | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 1c62001fce..68f8418f62 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -125,6 +125,14 @@ test_expect_success 'push new branch by name' '
 	compare_refs clone HEAD server refs/heads/new-name
 '
 
+test_expect_failure 'push new branch with old content' '
+	(cd clone &&
+	 git checkout -b existing &&
+	 git push origin existing
+	) &&
+	compare_refs clone refs/heads/existing server refs/heads/existing
+'
+
 test_expect_failure 'push new branch with old:new refspec' '
 	(cd clone &&
 	 git push origin new-name:new-refspec

From 75de40c45d939c93d51d4401498ecb6fb6514a89 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Fri, 15 Jul 2011 21:55:01 +0200
Subject: [PATCH 3329/3720] t5800: point out that deleting branches does not
 work

This test actually breaks the repositories involved somehow, so it is
not enabled by default.
---
 t/t5800-remote-helpers.sh | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 68f8418f62..0be4c7ef79 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -125,7 +125,7 @@ test_expect_success 'push new branch by name' '
 	compare_refs clone HEAD server refs/heads/new-name
 '
 
-test_expect_failure 'push new branch with old content' '
+test_expect_success 'push new branch with old content' '
 	(cd clone &&
 	 git checkout -b existing &&
 	 git push origin existing
@@ -133,6 +133,17 @@ test_expect_failure 'push new branch with old content' '
 	compare_refs clone refs/heads/existing server refs/heads/existing
 '
 
+test_expect_failure BROKEN 'delete branch' '
+	(cd clone &&
+	 git checkout -b delete-me &&
+	 echo content >>file &&
+	 git commit -a -m eight &&
+	 git push origin delete-me
+	 git push origin :delete-me) &&
+	test_must_fail git --git-dir="server/.git" rev-parse --verify delete-me
+'
+
+
 test_expect_failure 'push new branch with old:new refspec' '
 	(cd clone &&
 	 git push origin new-name:new-refspec

From ecef4383a75b1eaa5c51c9453b4ac1b630316601 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sat, 28 Aug 2010 20:49:01 -0500
Subject: [PATCH 3330/3720] transport-helper: add trailing --

---
 transport-helper.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/transport-helper.c b/transport-helper.c
index f6b3b1fb79..4bdccc665a 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -398,7 +398,7 @@ static int get_exporter(struct transport *transport,
 	/* we need to duplicate helper->in because we want to use it after
 	 * fastexport is done with it. */
 	fastexport->out = dup(helper->in);
-	fastexport->argv = xcalloc(5 + revlist_args->nr, sizeof(*fastexport->argv));
+	fastexport->argv = xcalloc(6 + revlist_args->nr, sizeof(*fastexport->argv));
 	fastexport->argv[argc++] = "fast-export";
 	fastexport->argv[argc++] = "--use-done-feature";
 	if (data->export_marks)
@@ -409,6 +409,8 @@ static int get_exporter(struct transport *transport,
 	for (i = 0; i < revlist_args->nr; i++)
 		fastexport->argv[argc++] = revlist_args->items[i].string;
 
+	fastexport->argv[argc++] = "--";
+
 	fastexport->git_cmd = 1;
 	return start_command(fastexport);
 }

From 8d98b97ebfffe894e20727e65024c1cb57644f5f Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 00:06:00 +0200
Subject: [PATCH 3331/3720] remote-helper: check helper status after
 import/export

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/clone.c    |  4 +++-
 transport-helper.c | 16 ++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index bbd5c96237..8e76a747aa 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -821,7 +821,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 			}
 
 		if (!is_local && !complete_refs_before_fetch)
-			transport_fetch_refs(transport, mapped_refs);
+			if (transport_fetch_refs(transport, mapped_refs))
+				die(_("could not fetch refs from %s"),
+				    transport->url);
 
 		remote_head = find_ref_by_name(refs, "HEAD");
 		remote_head_points_at =
diff --git a/transport-helper.c b/transport-helper.c
index 4bdccc665a..f157b627d0 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -415,6 +415,19 @@ static int get_exporter(struct transport *transport,
 	return start_command(fastexport);
 }
 
+static void check_helper_status(struct helper_data *data)
+{
+	int pid, status;
+
+	pid = waitpid(data->helper->pid, &status, WNOHANG);
+	if (pid < 0)
+		die("Could not retrieve status of remote helper '%s'",
+		    data->name);
+	if (pid > 0 && WIFEXITED(status))
+		die("Remote helper '%s' died with %d",
+		    data->name, WEXITSTATUS(status));
+}
+
 static int fetch_with_import(struct transport *transport,
 			     int nr_heads, struct ref **to_fetch)
 {
@@ -443,6 +456,8 @@ static int fetch_with_import(struct transport *transport,
 
 	if (finish_command(&fastimport))
 		die("Error while running fast-import");
+	check_helper_status(data);
+
 	free(fastimport.argv);
 	fastimport.argv = NULL;
 
@@ -771,6 +786,7 @@ static int push_refs_with_export(struct transport *transport,
 
 	if (finish_command(&exporter))
 		die("Error while running fast-export");
+	check_helper_status(data);
 	push_update_refs_status(data, remote_refs);
 	return 0;
 }

From 799a2243e9df8b11a4dd28c26f002558d658fab9 Mon Sep 17 00:00:00 2001
From: Matthieu Moy 
Date: Sat, 14 Jan 2012 19:55:36 +0100
Subject: [PATCH 3332/3720] bash-completion: don't add quoted space for ZSH
 (fix regression)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit a31e626 (completion: optimize refs completion) introduced a
regression for ZSH users: ref names were completed with a quoted trailing
space (i.e. "git checkout ma" completes to "git checkout master\ "). The
space is convenient for bash users since we use "-o nospace", but a
quoted space is worse than nothing. The absence of trailing space for ZSH
is a long-standing issue, that this patch is not fixing. We just fix the
regression by not appending a space when the shell is ZSH.

Original-patch-by: SZEDER Gábor 
Reported-by: Stefan Haller 
Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 contrib/completion/git-completion.bash | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 31f714da92..8d92094e42 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -509,6 +509,13 @@ __gitcomp ()
 __gitcomp_nl ()
 {
 	local IFS=$'\n'
+
+	# ZSH would quote the trailing space added with -S. bash users
+	# will appreciate the extra space to compensate the use of -o nospace.
+	if [ -n "${ZSH_VERSION-}" ] && [ "$suffix" = " " ]; then
+		suffix=""
+	fi
+
 	COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
 }
 

From 7d409158ff3cf859d0aafbc58e3f3f60ac233009 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 3333/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index be1957a5e9..073c3f67e6 100644
--- a/Makefile
+++ b/Makefile
@@ -1194,16 +1194,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 9636ced59552f23ad05104324d4b35026e881a17 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 3334/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index fb386abc51..a6f38e6ca0 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -184,6 +184,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index 0e708c478f..838d06824a 100644
--- a/cache.h
+++ b/cache.h
@@ -605,6 +605,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index a0ac487c0c..cc1b34999d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 0ff1e04812..699a3dd395 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -113,10 +113,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -318,6 +315,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index 68d32940f3..1759695d16 100644
--- a/config.c
+++ b/config.c
@@ -752,6 +752,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index d7e6c65763..d827d9e71d 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index ed11ad8119..14fa4e117a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -595,4 +595,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From e06710e043b42c9c7770a55505c15048e989ba8a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 3335/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index cc1b34999d..665f6abc40 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From e3d7115824656af8650f98b0456ad2313acfa6d0 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 3336/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 9b841961996e4d664090ad66af7e39b39a3d72ef Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 3337/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From abfc9ffa933035b3d7760c34578d8645544542a3 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 3338/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 795f156341c7d1e729ad299308bf2b7aa3e29a8e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 3339/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 22270ce46b..646fde8d10 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9575,7 +9575,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 689e6d32bc417b29ea11bbe69ea292c2ee2d7e5e Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 3340/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From f1d83863845a9188d361d610c95941674b6138f3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 3341/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 41c4f31faee0bbec20c6a2e79dd2f9d41bd3fac1 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 3342/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index a6f38e6ca0..49a24e5fb2 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1738,6 +1738,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 0afb8b2896..1b2bf5fe66 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -89,7 +91,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -410,6 +417,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -441,6 +486,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -469,6 +521,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b5417cc951..2482796454 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -995,4 +995,40 @@ test_expect_success 'push --prune refspec' '
 	! check_push_result $the_first_commit tmp/foo tmp/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 1198b74e217c32889e6994c6c42c74d2d4ac1aca Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 3343/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index ef30c557c7..c42fb2a7aa 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 35e117173ba7aa3ffc1d107be861aee9fa3d396f Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 3344/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index c42fb2a7aa..03292fd832 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From 2054a1c1ba68aa82c846da7ab3c58162eb72f0eb Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 3345/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 33c8820af6..c836ad063c 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -169,7 +169,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = given_config_file;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 665f6abc40..e5f1c36995 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1828,3 +1828,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 699a3dd395..ec5c25c36d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -349,3 +349,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index 1759695d16..53fd956a88 100644
--- a/config.c
+++ b/config.c
@@ -960,7 +960,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 14fa4e117a..5911e8f7eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -599,4 +599,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index 6f2aa699ad..4cb0585cde 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From f7ed539f09b4be74ef6581ba2457b8de165c4a55 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 3346/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 4da0ddafc4..ef7191e562 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -564,7 +564,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -736,7 +737,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -812,7 +814,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -836,7 +838,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From babf8d530d0d15b1cc58fd7b8f419991e5900e77 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 3347/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index b7d7100c4e..ca782c386a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From e626201283514aef22b6b8abaf705353ce9bdea0 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 3348/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index 838d06824a..91f4af3195 100644
--- a/cache.h
+++ b/cache.h
@@ -759,7 +759,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index e5f1c36995..39ce7b446d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1846,3 +1846,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index ec5c25c36d..9111ce66e7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -309,6 +309,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 5911e8f7eb..39866a76c2 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 4cb0585cde..242074b1cf 100644
--- a/path.c
+++ b/path.c
@@ -660,10 +660,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From c8d757712691925b25b9a512f64969ad337ed2af Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 3349/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index c836ad063c..e24586efa5 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;

From 7c9acdb95d7711df7cc4446d3b72149630d93862 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 3350/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 39ce7b446d..71adbc497a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,23 +1849,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 7265f630caa39c703290a5ac5d4757306357b111 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 3351/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 4de825ae30b6f80dca2ec1738405ce89e7cb7faa Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 3352/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 646fde8d10..3c2864fcf2 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -394,7 +394,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9575,18 +9575,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9597,6 +9586,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 56fe11bb6ca2a5a625805ebed8cf4c04a61e8929 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 3353/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 71adbc497a..fe3cae3a38 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1207,6 +1207,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 8e4a3e40606326c60a90a6b765d2e729c3707e58 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 3354/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9111ce66e7..60e281a7fe 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -290,9 +290,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From f4d368fef61f8c82cfbe537266dbb8f26dfe7276 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 3355/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 6a36cac842e72a76897a3cd55e8635c47a0bdb26 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 3356/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 638a2f6a7e45e326928602f46a6a9d97b866992d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 3357/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index cea8756866..9be97ab9ae 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From a83c5b8172a8b6abcd6cbccf258acc856198da61 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 3358/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a8b5fad266..ec97589687 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4434,6 +4434,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From b890607030d669fcb727f3cc8075905182322958 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 3359/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index ec97589687..3c2284f611 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4449,7 +4449,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From e1de98ddde8683f6bcbf06b07476b6ba67098446 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 3360/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 3e51d6cbe9..3013849db0 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -140,6 +141,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -147,17 +160,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 0a8611c4164766ef80592e810b05afcbc507aebe Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 3361/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 1b2bf5fe66..b648c14a86 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -420,7 +420,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 1743aae8c8ce13fd8e81d679b11d35ff53efcf69 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 3362/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 643938d905..cda17f775a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -162,6 +163,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -172,6 +189,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->source.identifier))
+			continue;
+
 		opt->output_priv = w;
 		hit |= grep_source(opt, &w->source);
 		grep_source_clear_data(&w->source);
@@ -418,6 +438,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -883,6 +906,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 4d0fc2038dc2bd2d84d8379cee77be3035c66342 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 3363/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 073c3f67e6..c7c90e5f33 100644
--- a/Makefile
+++ b/Makefile
@@ -308,7 +308,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From 72300af344cfa2b8db674b36aa4dcd80239666ec Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 3364/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index fe3cae3a38..f86800680c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1833,7 +1833,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From f5ba0c558123bbde092a699456ae4bf34c23dd2d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 3365/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c7c90e5f33..5223417b99 100644
--- a/Makefile
+++ b/Makefile
@@ -2093,7 +2093,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2133,6 +2133,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 8275cf772ddad5790af00909f1835a5332ff7d32 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 3366/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e661147c57..18a93cba9f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From fad3722efdcf0784d9d4c7ec114ca6f0c6393f75 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 3367/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index cda17f775a..3af417e76c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -974,6 +974,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From 4f0d01ab8e5b4342f852006e0ef610af051b45c8 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 3368/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index 497f420178..266c1236ff 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From f44e2549db8935a6eb5a0c6387f13bff93fffd47 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 3369/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f86800680c..61a1230433 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From f0bdde47f8db0ae94511082956c03e7aa4dbb1d0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 3370/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 2cb6123129dd83b743f8cb0f707a3bea32d9c7d8 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 3371/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 3372/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index efc86ad4e0..5bec652114 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -832,12 +832,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 3373/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 6fad55f2d134bcd7c444cf37908d1aaf0c4ec317 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 3374/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 5d8e4e6c89..d9fc4be050 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 3375/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 5223417b99..7879caa174 100644
--- a/Makefile
+++ b/Makefile
@@ -1188,6 +1188,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1281,6 +1282,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 5b9bfb51f33a6dc600909718f650862625f9bb2c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 3376/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 53b02733ec6ecd96d8f6af38ef16060a2e9bdc5c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 3377/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From a311684a1cd849a76c663879e615e50a247508ac Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 3378/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 8dc8a639fb260e24e956e198cb9f246be34497dc Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 3379/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 24b70052230acd751d9d966024535aaacf331a88 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 3380/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 61a1230433..398c11f175 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 1eccee6ac4272bc65d4fedfc2ceb670faeb85766 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 3381/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 398c11f175..8565118abd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1875,3 +1875,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 60e281a7fe..da9c53583a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -330,22 +330,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 7fa1d0823f18143a85a268fcabf0a620304fd441 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 3382/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8565118abd..1b40ff2373 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1876,6 +1876,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 4c80579de05d285b6e30a85032526b5f7afb7da4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 3383/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 3c2284f611..e032b69aff 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6812,7 +6812,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -6860,6 +6872,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 20faa8819c6474c040e0309f166092b533fb7e85 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 3384/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e032b69aff..5dbbcfa0ba 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4434,7 +4434,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 47d08c46de8d565b5293994f4b66f37c52c42ce2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 3385/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 5dbbcfa0ba..14a133ae00 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6925,7 +6925,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 7e2a1303fbfe55aa029c929417b4b36ac91011bc Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 3386/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1b40ff2373..952a2a6819 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 2d16ba13315690392e81ebb528ffed9dbf3fe916 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 21 Sep 2011 08:33:28 +0200
Subject: [PATCH 3387/3720] Windows: define S_ISUID properly

8fb3ad76 (fast-import: prevent producing bad delta) introduced the first
use of S_ISUID. Since before this commit the value was irrelevant, we had
only a dummy definition in mingw.h. But beginning with this commit the
macro must expand to a reasonable value. Make it so.

We do not change S_ISGID from the value 0 because it is used in path.c
(via FORCE_DIR_SET_GID) to set the mode on directories in a manner that
is not supported on Windows, and 0 is the right value in this case.

Signed-off-by: Johannes Sixt 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index da9c53583a..1f9f35f63d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -22,7 +22,7 @@ typedef int socklen_t;
 #define S_IWOTH 0
 #define S_IXOTH 0
 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0
+#define S_ISUID 04000
 #define S_ISGID 0
 #define S_ISVTX 0
 

From 816629f71951f887808ab66b0188105552c342d8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 3388/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0f18ec891a..a5506a83c5 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `{litdd}rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 2a10047eb7..be1b098be0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -113,7 +114,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -278,7 +284,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From d48b69bc024c2d12e679571f81b9525570ca4826 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 3389/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 49a24e5fb2..1e76b4c2e1 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -714,6 +714,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index be1b098be0..34b47c4fb2 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 5523248f01b1d4c86b102d4bdee919c5b1bad071 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 3390/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1f9f35f63d..407bad231b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 39866a76c2..76c5eef420 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From e26fe8bf3e728d4a45aed9134a9d1f659e8f7f94 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 3391/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From b0c7fed9f6b87f99e728b5cb8b8c6250f3768448 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 3392/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 7879caa174..3ad3062305 100644
--- a/Makefile
+++ b/Makefile
@@ -1186,6 +1186,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From 09a855800adb08333d7b1f351f1af1e8cb85315b Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 3393/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From 53dcd84491cfd92d0c4c2537f06cf0f6e9ba853d Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 3394/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3ad3062305..4dc9256967 100644
--- a/Makefile
+++ b/Makefile
@@ -1264,7 +1264,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From a6f77912b4c067921fd1bcbf5634a6e4bfd5cc96 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 3395/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 4dc9256967..c82f297f0f 100644
--- a/Makefile
+++ b/Makefile
@@ -1301,6 +1301,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From 0ffccd925e9112197e4a900d494b5deccaeff71c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 3396/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From 77b8f77a864246c6b80eb16b3227d32227e1baeb Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 18:15:31 +0100
Subject: [PATCH 3397/3720] Windows/i18n: rename $path to prevent clashes with
 $PATH

Environment variables on Windows are case-insensitive. Rename '$path' in
all calls to eval_gettext to $modulepath so that it is not mistakenly
expanded to the value of the $PATH variable.

[jes: this happens to fix t7406/t7407 on Windows]
[pt: squashed in fix for substitution order error that broke t7400]

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
---
 git-submodule.sh | 52 ++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index dccd0f663a..efb0cfdfe9 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -105,7 +105,7 @@ module_name()
 	name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
 	test -z "$name" &&
-	die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+	die "$(modulepath=$path eval_gettext "No submodule mapping found in .gitmodules for path '\$modulepath'")"
 	echo "$name"
 }
 
@@ -146,7 +146,7 @@ module_clone()
 		mkdir -p "$gitdir_base"
 		git clone $quiet -n ${reference:+"$reference"} \
 			--separate-git-dir "$gitdir" "$url" "$path" ||
-		die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+		die "$(modulepath=$path eval_gettext "Clone of '\$url' into submodule path '\$modulepath' failed")"
 	fi
 
 	a=$(cd "$gitdir" && pwd)/
@@ -261,13 +261,13 @@ cmd_add()
 			s|/*$||
 		')
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
-	die "$(eval_gettext "'\$path' already exists in the index")"
+	die "$(modulepath=$path eval_gettext "'\$modulepath' already exists in the index")"
 
 	if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
 	then
 		cat >&2 </dev/null) &&
 					 test -z "$rev") || git-fetch)) ||
-				die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
+				die "$(modulepath=$path eval_gettext "Unable to fetch in submodule path '\$modulepath'")"
 			fi
 
 			# Is this something we just cloned?
@@ -564,20 +564,20 @@ Maybe you want to use 'update --init'?")"
 			case "$update_module" in
 			rebase)
 				command="git rebase"
-				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to rebase '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': rebased into '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			merge)
 				command="git merge"
-				die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to merge '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': merged in '\$sha1'")"
 				must_die_on_failure=yes
 				;;
 			*)
 				command="git checkout $subforce -q"
-				die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
-				say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
+				die_msg="$(modulepath=$path eval_gettext "Unable to checkout '\$sha1' in submodule path '\$modulepath'")"
+				say_msg="$(modulepath=$path eval_gettext "Submodule path '\$modulepath': checked out '\$sha1'")"
 				;;
 			esac
 
@@ -599,7 +599,7 @@ Maybe you want to use 'update --init'?")"
 			res=$?
 			if test $res -gt 0
 			then
-				die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+				die_msg="$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 				if test $res -eq 1
 				then
 					err="${err};$die_msg"
@@ -926,7 +926,7 @@ cmd_status()
 				cd "$path" &&
 				eval cmd_status "$orig_args"
 			) ||
-			die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
+			die "$(modulepath=$path eval_gettext "Failed to recurse into submodule path '\$modulepath'")"
 		fi
 	done
 }

From 0e80c6cbcf703ccac2cbe421f0547249d132e43e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 3 Feb 2012 00:12:04 -0600
Subject: [PATCH 3398/3720] Teach 'git remote' that the config var
 branch.*.rebase can be 'interactive'

Signed-off-by: Johannes Schindelin 
---
 builtin/remote.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index fec92bc66e..7b37a23d97 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -253,7 +253,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	int rebase;
+	enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
 };
 
 static struct string_list branch_list;
@@ -310,7 +310,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			}
 			string_list_append(&info->merge, xstrdup(value));
 		} else
-			info->rebase = git_config_bool(orig_key, value);
+			info->rebase = value && *value == 'i' ?
+				INTERACTIVE_REBASE :
+				(git_config_bool(orig_key, value) ?
+				 NORMAL_REBASE : NO_REBASE);
 	}
 	return 0;
 }
@@ -994,7 +997,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf("rebases onto remote %s\n", merge->items[0].string);
+		printf("rebases %sonto remote %s\n",
+			branch_info->rebase == INTERACTIVE_REBASE ?
+			"interactively " : "", merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf(" merges with remote %s\n", merge->items[0].string);

From e00961e1cf0a9aa6a667af00808d8e8b57e53e15 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:28:37 +0100
Subject: [PATCH 3399/3720] git-gui: fix encoding in git-gui file browser

Assume git tree objects (i.e. output of git-ls-tree) are encoded in system
encoding, for display in the git-gui file browser.

Signed-off-by: Karsten Blees 
---
 git-gui/lib/browser.tcl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 0328338fda..4fca8fb13c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary -encoding binary
+	fconfigure $fd -blocking 0 -translation binary
 	fileevent $fd readable [cb _read $fd]
 }
 

From 5af6fb94b9f9229e77f4376c1a7a8e07e581aa1d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:38:07 +0100
Subject: [PATCH 3400/3720] gitk: fix file name encoding in diff hunk headers

Decode file names from system encoding in all diff hunk header lines, not
just the first (i.e. print nice file names in 'rename from' / 'rename to' /
'Binary files' lines, too).

Signed-off-by: Karsten Blees 
---
 gitk-git/gitk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 3c2864fcf2..16ff52a2c1 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7855,6 +7855,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
+	    set line [encoding convertfrom $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {

From c7f98925ba308a76e3890aa36b25310f9bf5040e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 19:06:41 +0100
Subject: [PATCH 3401/3720] Revert "Windows: teach getenv to do a
 case-sensitive search"

This reverts commit df599e9612788b728ce43a03159b85f1fe624d6a.

As of 5e9637c6 "i18n: add infrastructure for translating Git with gettext",
eval_gettext uses MinGW envsubst.exe instead of git-sh-i18n--envsubst.exe
for variable substitution. This breaks git-submodule.sh messages and tests,
as envsubst.exe doesn't support case-sensitive environment lookup (the same
is true for almost everything on Windows, including MSys and Cygwin tools).

30a615ac "Windows/i18n: rename $path to prevent clashes with $PATH" renames
the conflicting variable in git-submodule.sh, so that it works on Windows
(i.e. with case-insensitive environment, regardless of the toolset).

Revert to the documented behaviour of case-insensitive environment on
Windows.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 952a2a6819..1135b4bb78 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1182,31 +1182,14 @@ char **make_augmented_environ(const char *const *vars)
 }
 
 #undef getenv
-
-/*
- * The system's getenv looks up the name in a case-insensitive manner.
- * This version tries a case-sensitive lookup and falls back to
- * case-insensitive if nothing was found.  This is necessary because,
- * as a prominent example, CMD sets 'Path', but not 'PATH'.
- * Warning: not thread-safe.
- */
-static char *getenv_cs(const char *name)
-{
-	size_t len = strlen(name);
-	int i = lookup_env(environ, name, len);
-	if (i >= 0)
-		return environ[i] + len + 1;	/* skip past name and '=' */
-	return getenv(name);
-}
-
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv_cs(name);
+	char *result = getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv_cs("TMP");
+		result = getenv("TMP");
 		if (!result)
-			result = getenv_cs("TEMP");
+			result = getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */

From 3d0271a5d8c62c614bf7203533c3aad55ae513cc Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:19:31 +0100
Subject: [PATCH 3402/3720] Revert "mingw.c: move definition of mingw_getenv
 down"

This reverts commit 06bc4b796ad69ba93f0a8c451368602e0553c2d3.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1135b4bb78..649c6857dd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -180,7 +180,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	vsnprintf(question, sizeof(question), format, args);
 	va_end(args);
 
-	if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
+	if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
 		retry_hook[1] = question;
 		return !run_command_v_opt(retry_hook, 0);
 	}
@@ -665,6 +665,23 @@ char *mingw_getcwd(char *pointer, int len)
 	return ret;
 }
 
+#undef getenv
+char *mingw_getenv(const char *name)
+{
+	char *result = getenv(name);
+	if (!result && !strcmp(name, "TMPDIR")) {
+		/* on Windows it is TMP and TEMP */
+		result = getenv("TMP");
+		if (!result)
+			result = getenv("TEMP");
+	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
+	return result;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -764,7 +781,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-	char *p, **path, *envpath = mingw_getenv("PATH");
+	char *p, **path, *envpath = getenv("PATH");
 	int i, n = 0;
 
 	if (!envpath || !*envpath)
@@ -1181,23 +1198,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-	char *result = getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
-		if (!result)
-			result = getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From e6ee9ac174f4c803a48adb8be241e6b0bc079a5a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:24:19 +0100
Subject: [PATCH 3403/3720] Win32: Thread-safe windows console output

Winansi.c has many static variables that are accessed and modified from
the [v][f]printf / fputs functions overridden in the file. This may cause
multi threaded git commands that print to the console to produce corrupted
output or even crash.

Additionally, winansi.c doesn't override all functions that can be used to
print to the console (e.g. fwrite, write, fputc are missing), so that ANSI
escapes don't work properly for some git commands (e.g. git-grep).

Instead of doing ANSI emulation in just a few wrapped functions on top of
the IO API, let's plug into the IO system and take advantage of the thread
safety inherent to the IO system.

Redirect stdout and stderr to a pipe if they point to the console. A
background thread reads from the pipe, handles ANSI escape sequences and
UTF-8 to UTF-16 conversion, then writes to the console.

The pipe-based stdout and stderr replacements must be set to unbuffered, as
MSVCRT doesn't support line buffering and fully buffered streams are
inappropriate for console output.

Due to the byte-oriented pipe, ANSI escape sequences and multi-byte UTF-8
sequences can no longer be expected to arrive in one piece. Replace the
string-based ansi_emulate() with a simple stateful parser (this also fixes
colored diff hunk headers, which were broken as of commit 2efcc977).

Override isatty to return true for the pipes redirecting to the console.

Exec/spawn obtain the original console handle to pass to the next process
via winansi_get_osfhandle().

All other overrides are gone, the default stdio implementations work as
expected with the piped stdout/stderr descriptors.

Global variables are either initialized on startup (single threaded) or
exclusively modified by the background thread. Threads communicate through
the pipe, no further synchronization is necessary.

The background thread is terminated by disonnecting the pipe after flushing
the stdio and pipe buffers. This doesn't work for anonymous pipes (created
via CreatePipe), as DisconnectNamedPipe only works on the read end, which
discards remaining data. Thus we have to setup the pipe manually, with the
write end beeing the server (opened with CreateNamedPipe) and the read end
the client (opened with CreateFile).

Limitations: doesn't track reopened or duped file descriptors, i.e.:
- fdopen(1/2) returns fully buffered streams
- dup(1/2), dup2(1/2) returns normal pipe descriptors (i.e. isatty() =
  false, winansi_get_osfhandle won't return the original console handle)

Currently, only the git-format-patch command uses xfdopen(xdup(1)) (see
"realstdout" in builtin/log.c), but works well with these limitations.

Many thanks to Atsushi Nakagawa  for suggesting and
reviewing the thread-exit-mechanism.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c   |   9 +-
 compat/mingw.h   |  12 +-
 compat/winansi.c | 420 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 282 insertions(+), 159 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 649c6857dd..190e7b7681 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -917,9 +917,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	memset(&si, 0, sizeof(si));
 	si.cb = sizeof(si);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-	si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-	si.hStdError = (HANDLE) _get_osfhandle(fherr);
+	si.hStdInput = winansi_get_osfhandle(fhin);
+	si.hStdOutput = winansi_get_osfhandle(fhout);
+	si.hStdError = winansi_get_osfhandle(fherr);
 
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
@@ -1878,4 +1878,7 @@ void mingw_startup()
 	_setmode(_fileno(stdin), _O_BINARY);
 	_setmode(_fileno(stdout), _O_BINARY);
 	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
 }
diff --git a/compat/mingw.h b/compat/mingw.h
index 407bad231b..2683adcaf7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -288,14 +288,10 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-int winansi_vfprintf(FILE *stream, const char *format, va_list list);
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
-#define vfprintf winansi_vfprintf
+void winansi_init(void);
+int winansi_isatty(int fd);
+HANDLE winansi_get_osfhandle(int fd);
+#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index bec6713b74..a3e4d88295 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,18 +4,13 @@
 
 #undef NOGDI
 #include "../git-compat-util.h"
-#include 
 #include 
 #include 
 
 /*
  Functions to be wrapped:
 */
-#undef printf
-#undef fprintf
-#undef fputs
-#undef vfprintf
-/* TODO: write */
+#undef isatty
 
 /*
  ANSI codes used by git: m, K
@@ -28,7 +23,10 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
-static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hwrite1 = INVALID_HANDLE_VALUE, hwrite2 = INVALID_HANDLE_VALUE;
+static HANDLE hconsole1, hconsole2;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -44,27 +42,19 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void print_font_warning(void)
+static void warn_if_raster_font(void)
 {
-	warning("Your console font probably doesn\'t support Unicode. If "
-		"you experience strange characters in the output, consider "
-		"switching to a TrueType font such as Lucida Console!");
-}
-
-static void check_truetype_font(void)
-{
-	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't do this twice */
-	if (truetype_font_checked)
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
 		return;
-	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
+			GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);
@@ -73,8 +63,8 @@ static void check_truetype_font(void)
 	} else {
 		/* pre-Vista: check default console font in registry */
 		HKEY hkey;
-		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
-				KEY_READ, &hkey)) {
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+				0, KEY_READ, &hkey)) {
 			DWORD size = sizeof(fontFamily);
 			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
 					(LPVOID) &fontFamily, &size);
@@ -82,61 +72,63 @@ static void check_truetype_font(void)
 		}
 	}
 
-	if (!(fontFamily & TMPF_TRUETYPE))
-		atexit(print_font_warning);
+	if (!(fontFamily & TMPF_TRUETYPE)) {
+		const wchar_t *msg = L"\nWarning: Your console font probably "
+			L"doesn\'t support Unicode. If you experience strange "
+			L"characters in the output, consider switching to a "
+			L"TrueType font such as Lucida Console!\n";
+		WriteConsoleW(console, msg, wcslen(msg), NULL, NULL);
+	}
 }
 
-static int is_console(FILE *stream)
+static int is_console(int fd)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
 	HANDLE hcon;
 
 	static int initialized = 0;
 
-	/* use cached value if stream hasn't changed */
-	if (stream == last_stream)
-		return console != NULL;
-
-	last_stream = stream;
-	console = NULL;
-
-	/* get OS handle of the stream */
-	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	/* get OS handle of the file descriptor */
+	hcon = (HANDLE) _get_osfhandle(fd);
 	if (hcon == INVALID_HANDLE_VALUE)
 		return 0;
 
+	/* check if its a device (i.e. console, printer, serial port) */
+	if (GetFileType(hcon) != FILE_TYPE_CHAR)
+		return 0;
+
 	/* check if its a handle to a console output screen buffer */
 	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
+	/* initialize attributes */
 	if (!initialized) {
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
 	}
 
-	console = hcon;
 	return 1;
 }
 
-static int write_console(const char *str, size_t len)
-{
-	/* convert utf-8 to utf-16, write directly to console */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
-	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
-	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
 
+static void write_console(unsigned char *str, size_t len)
+{
+	/* only called from console_thread, so a static buffer will do */
+	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+
+	/* convert utf-8 to utf-16 */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
+			ARRAY_SIZE(wbuf));
+
+	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/*
-	 * if non-ascii characters are printed, check that the current console
-	 * font supports this
-	 */
+	/* remember if non-ascii characters are printed */
 	if (wlen != len)
-		check_truetype_font();
-
-	/* return original (utf-8 encoded) length */
-	return len;
+		non_ascii_used = 1;
 }
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
@@ -182,18 +174,13 @@ static void erase_in_line(void)
 		&dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-	const char *func;
-	size_t len = strspn(str, "0123456789;");
-	func = str + len;
-
-	switch (*func) {
+	int i;
+	switch (func) {
 	case 'm':
-		do {
-			long val = strtol(str, (char **)&str, 10);
-			switch (val) {
+		for (i = 0; i < paramlen; i++) {
+			switch (params[i]) {
 			case 0: /* reset */
 				attr = plain_attr;
 				negative = 0;
@@ -316,9 +303,7 @@ static const char *set_attr(const char *str)
 				/* Unsupported code */
 				break;
 			}
-			str++;
-		} while (*(str-1) == ';');
-
+		}
 		set_console_attr();
 		break;
 	case 'K':
@@ -328,112 +313,251 @@ static const char *set_attr(const char *str)
 		/* Unsupported code */
 		break;
 	}
-
-	return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+	TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-	int rv = 0;
-	const char *pos = str;
+	unsigned char buffer[BUFFER_SIZE];
+	DWORD bytes;
+	int start, end = 0, c, parampos = 0, state = TEXT;
+	int params[MAX_PARAMS];
 
-	fflush(stream);
+	while (1) {
+		/* read next chunk of bytes from the pipe */
+		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+				NULL)) {
+			/* exit if pipe has been closed or disconnected */
+			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+					GetLastError() == ERROR_BROKEN_PIPE)
+				break;
+			/* ignore other errors */
+			continue;
+		}
 
-	while (*pos) {
-		pos = strstr(str, "\033[");
-		if (pos) {
-			size_t len = pos - str;
+		/* scan the bytes and handle ANSI control codes */
+		bytes += end;
+		start = end = 0;
+		while (end < bytes) {
+			c = buffer[end++];
+			switch (state) {
+			case TEXT:
+				if (c == ESCAPE) {
+					/* print text seen so far */
+					if (end - 1 > start)
+						write_console(buffer + start,
+							end - 1 - start);
 
-			if (len) {
-				size_t out_len = write_console(str, len);
-				rv += out_len;
-				if (out_len < len)
-					return rv;
+					/* then start parsing escape sequence */
+					start = end - 1;
+					memset(params, 0, sizeof(params));
+					parampos = 0;
+					state = ESCAPE;
+				}
+				break;
+
+			case ESCAPE:
+				/* continue if "\033[", otherwise bail out */
+				state = (c == BRACKET) ? BRACKET : TEXT;
+				break;
+
+			case BRACKET:
+				/* parse [0-9;]* into array of parameters */
+				if (c >= '0' && c <= '9') {
+					params[parampos] *= 10;
+					params[parampos] += c - '0';
+				} else if (c == ';') {
+					/*
+					 * next parameter, bail out if out of
+					 * bounds
+					 */
+					parampos++;
+					if (parampos >= MAX_PARAMS)
+						state = TEXT;
+				} else {
+					/*
+					 * end of escape sequence, change
+					 * console attributes
+					 */
+					set_attr(c, params, parampos + 1);
+					start = end;
+					state = TEXT;
+				}
+				break;
+			}
+		}
+
+		/* print remaining text unless parsing an escape sequence */
+		if (state == TEXT && end > start) {
+			/* check for incomplete UTF-8 sequences and fix end */
+			if (buffer[end - 1] >= 0x80) {
+				if (buffer[end -1] >= 0xc0)
+					end--;
+				else if (end - 1 > start &&
+						buffer[end - 2] >= 0xe0)
+					end -= 2;
+				else if (end - 2 > start &&
+						buffer[end - 3] >= 0xf0)
+					end -= 3;
 			}
 
-			str = pos + 2;
-			rv += 2;
+			/* print remaining complete UTF-8 sequences */
+			if (end > start)
+				write_console(buffer + start, end - start);
 
-			pos = set_attr(str);
-			rv += pos - str;
-			str = pos;
+			/* move remaining bytes to the front */
+			if (end < bytes)
+				memmove(buffer, buffer + end, bytes - end);
+			end = bytes - end;
 		} else {
-			size_t len = strlen(str);
-			rv += write_console(str, len);
-			return rv;
+			/* all data has been consumed, mark buffer empty */
+			end = 0;
 		}
 	}
-	return rv;
+
+	/* check if the console font supports unicode */
+	warn_if_raster_font();
+
+	CloseHandle(hread);
+	return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-	int rv;
+	/* flush all streams */
+	_flushall();
 
-	if (!is_console(stream))
-		return fputs(str, stream);
+	/* signal console thread to exit */
+	FlushFileBuffers(hwrite);
+	DisconnectNamedPipe(hwrite);
 
-	rv = ansi_emulate(str, stream);
+	/* wait for console thread to copy remaining data */
+	WaitForSingleObject(hthread, INFINITE);
 
-	if (rv >= 0)
-		return 0;
+	/* cleanup handles... */
+	if (hwrite1 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite1);
+	if (hwrite2 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite2);
+	CloseHandle(hwrite);
+	CloseHandle(hthread);
+}
+
+static void die_lasterr(const char *fmt, ...)
+{
+	va_list params;
+	va_start(params, fmt);
+	errno = err_win_to_posix(GetLastError());
+	die_errno(fmt, params);
+	va_end(params);
+}
+
+static HANDLE duplicate_handle(HANDLE hnd)
+{
+	HANDLE hresult, hproc = GetCurrentProcess();
+	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+			DUPLICATE_SAME_ACCESS))
+		die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+	return hresult;
+}
+
+static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+{
+	/* get original console handle */
+	int fd = _fileno(stream);
+	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
+	if (hcon == INVALID_HANDLE_VALUE)
+		die_errno("_get_osfhandle(%i) failed", fd);
+
+	/* save a copy to phcon and console (used by the background thread) */
+	console = *phcon = duplicate_handle(hcon);
+
+	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
+	if (_dup2(new_fd, fd))
+		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+
+	/* no buffering, or stdout / stderr will be out of sync */
+	setbuf(stream, NULL);
+	return (HANDLE) _get_osfhandle(fd);
+}
+
+void winansi_init(void)
+{
+	int con1, con2, hwrite_fd;
+	char name[32];
+
+	/* check if either stdout or stderr is a console output screen buffer */
+	con1 = is_console(1);
+	con2 = is_console(2);
+	if (!con1 && !con2)
+		return;
+
+	/* create a named pipe to communicate with the console thread */
+	sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+	hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+	if (hwrite == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateNamedPipe failed");
+
+	hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (hread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateFile for named pipe failed");
+
+	/* start console spool thread on the pipe's read end */
+	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+	if (hthread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateThread(console_thread) failed");
+
+	/* schedule cleanup routine */
+	if (atexit(winansi_exit))
+		die_errno("atexit(winansi_exit) failed");
+
+	/* create a file descriptor for the write end of the pipe */
+	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
+	if (hwrite_fd == -1)
+		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
+
+	/* redirect stdout / stderr to the pipe */
+	if (con1)
+		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+	if (con2)
+		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
+
+	/* close pipe file descriptor (also closes the duped hwrite) */
+	close(hwrite_fd);
+}
+
+static int is_same_handle(HANDLE hnd, int fd)
+{
+	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
+}
+
+/*
+ * Return true if stdout / stderr is a pipe redirecting to the console.
+ */
+int winansi_isatty(int fd)
+{
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return 1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return 1;
 	else
-		return EOF;
+		return isatty(fd);
 }
 
-int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-	int len, rv;
-	char small_buf[256];
-	char *buf = small_buf;
-	va_list cp;
-
-	if (!is_console(stream))
-		goto abort;
-
-	va_copy(cp, list);
-	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-	va_end(cp);
-
-	if (len > sizeof(small_buf) - 1) {
-		buf = malloc(len + 1);
-		if (!buf)
-			goto abort;
-
-		len = vsnprintf(buf, len + 1, format, list);
-	}
-
-	rv = ansi_emulate(buf, stream);
-
-	if (buf != small_buf)
-		free(buf);
-	return rv;
-
-abort:
-	rv = vfprintf(stream, format, list);
-	return rv;
-}
-
-int winansi_fprintf(FILE *stream, const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stream, format, list);
-	va_end(list);
-
-	return rv;
-}
-
-int winansi_printf(const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stdout, format, list);
-	va_end(list);
-
-	return rv;
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return hconsole1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return hconsole2;
+	else
+		return (HANDLE) _get_osfhandle(fd);
 }

From 4575d0326ecc81fac3a4202b06e397af1658169d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:05:06 +0100
Subject: [PATCH 3404/3720] Win32: add Unicode conversion functions

Add Unicode conversion functions to convert between Windows native UTF-16LE
encoding to UTF-8 and back.

To support repositories with legacy-encoded file names, the UTF-8 to UTF-16
conversion function tries to create valid, unique file names even for
invalid UTF-8 byte sequences, so that these repositories can be checked out
without error.

The current implementation leaves invalid UTF-8 bytes in range 0xa0 - 0xff
as is (producing printable Unicode chars \u00a0 - \u00ff, equivalent to
ISO-8859-1), and converts 0x80 - 0x9f to hex-code (\u0080 - \u009f are
control chars).

The Windows MultiByteToWideChar API was not used as it either drops invalid
UTF-8 sequences (on Win2k/XP; producing non-unique or even empty file
names) or converts them to the replacement char \ufffd (Vista/7; causing
ERROR_INVALID_NAME in subsequent calls to file system APIs).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c |  85 ++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 190e7b7681..8ed43f9bf1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1859,6 +1859,91 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
diff --git a/compat/mingw.h b/compat/mingw.h
index 2683adcaf7..ddb228473b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -326,6 +326,110 @@ void mingw_mark_as_git_dir(const char *dir);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A replacement of main() that adds win32 specific initialization.
  */

From 771bb1453827d8ccdc2a9ef29a4a367beabd06d9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 18:21:28 +0100
Subject: [PATCH 3405/3720] Win32: Unicode file name support (except dirent)

Replaces Windows "ANSI" APIs dealing with file- or path names with their
Unicode equivalent, adding UTF-8/UTF-16LE conversion as necessary.

The dirent API (opendir/readdir/closedir) is updated in a separate commit.

Adds trivial wrappers for access, chmod and chdir.

Adds wrapper for mktemp (needed for both mkstemp and mkdtemp).

The simplest way to convert a repository with legacy-encoded (e.g. Cp1252)
file names to UTF-8 ist to checkout with an old msysgit version and
"git add --all & git commit" with the new version.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 210 ++++++++++++++++++++++++++++++++++---------------
 compat/mingw.h |  13 +++
 2 files changed, 158 insertions(+), 65 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8ed43f9bf1..5d5f30bd2c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "win32.h"
 #include 
+#include 
 #include "../strbuf.h"
 #include "../run-command.h"
 #include "../cache.h"
@@ -200,14 +201,16 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	}
 }
 
-#undef unlink
 int mingw_unlink(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
 	/* read-only files cannot be removed */
-	chmod(pathname, 0666);
-	while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
 		/*
@@ -223,43 +226,40 @@ int mingw_unlink(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = unlink(pathname);
+	       ret = _wunlink(wpathname);
 	return ret;
 }
 
-static int is_dir_empty(const char *path)
+static int is_dir_empty(const wchar_t *wpath)
 {
-	struct strbuf buf = STRBUF_INIT;
-	WIN32_FIND_DATAA findbuf;
+	WIN32_FIND_DATAW findbuf;
 	HANDLE handle;
-
-	strbuf_addf(&buf, "%s\\*", path);
-	handle = FindFirstFileA(buf.buf, &findbuf);
-	if (handle == INVALID_HANDLE_VALUE) {
-		strbuf_release(&buf);
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
 		return GetLastError() == ERROR_NO_MORE_FILES;
-	}
 
-	while (!strcmp(findbuf.cFileName, ".") ||
-			!strcmp(findbuf.cFileName, ".."))
-		if (!FindNextFile(handle, &findbuf)) {
-			strbuf_release(&buf);
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf))
 			return GetLastError() == ERROR_NO_MORE_FILES;
-		}
 	FindClose(handle);
-	strbuf_release(&buf);
 	return 0;
 }
 
-#undef rmdir
 int mingw_rmdir(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
-	while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
-		if (!is_dir_empty(pathname)) {
+		if (!is_dir_empty(wpathname)) {
 			errno = ENOTEMPTY;
 			break;
 		}
@@ -276,14 +276,14 @@ int mingw_rmdir(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = rmdir(pathname);
+	       ret = _wrmdir(wpathname);
 	return ret;
 }
 
-static int make_hidden(const char *path)
+static int make_hidden(const wchar_t *path)
 {
-	DWORD attribs = GetFileAttributes(path);
-	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+	DWORD attribs = GetFileAttributesW(path);
+	if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
 		return 0;
 	errno = err_win_to_posix(GetLastError());
 	return -1;
@@ -291,19 +291,23 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
-	    make_hidden(dir))
-		warning("Failed to make '%s' hidden", dir);
+	wchar_t wdir[MAX_PATH];
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
+		if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
+			warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
 		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
 		 "dotGitOnly" : "true"));
 }
 
-#undef mkdir
 int mingw_mkdir(const char *path, int mode)
 {
-	int ret = mkdir(path);
+	int ret;
+	wchar_t wpath[MAX_PATH];
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
 	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
 		/*
 		 * In Windows a file or dir starting with a dot is not
@@ -312,17 +316,17 @@ int mingw_mkdir(const char *path, int mode)
 		 */
 		const char *start = basename((char*)path);
 		if (*start == '.')
-			return make_hidden(path);
+			return make_hidden(wpath);
 	}
 	return ret;
 }
 
-#undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
 	va_list args;
 	unsigned mode;
 	int fd;
+	wchar_t wfilename[MAX_PATH];
 
 	va_start(args, oflags);
 	mode = va_arg(args, int);
@@ -331,10 +335,12 @@ int mingw_open (const char *filename, int oflags, ...)
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
 
-	fd = open(filename, oflags, mode);
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	fd = _wopen(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
-		DWORD attrs = GetFileAttributes(filename);
+		DWORD attrs = GetFileAttributesW(wfilename);
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
@@ -346,7 +352,7 @@ int mingw_open (const char *filename, int oflags, ...)
 		 * such a file is created.
 		 */
 		const char *start = basename((char*)filename);
-		if (*start == '.' && make_hidden(filename))
+		if (*start == '.' && make_hidden(wfilename))
 			warning("Could not mark '%s' as hidden.", filename);
 	}
 	return fd;
@@ -369,38 +375,69 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 	return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
-#undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = fopen(filename, otype);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfopen(wfilename, wotype);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
-#undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = freopen(filename, otype, stream);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -426,10 +463,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
  */
 static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
-	int err;
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
-	if (!(err = get_file_attr(file_name, &fdata))) {
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
 		buf->st_ino = 0;
 		buf->st_gid = 0;
 		buf->st_uid = 0;
@@ -442,8 +481,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-			WIN32_FIND_DATAA findbuf;
-			HANDLE handle = FindFirstFileA(file_name, &findbuf);
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
 			if (handle != INVALID_HANDLE_VALUE) {
 				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
 						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
@@ -462,7 +501,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		}
 		return 0;
 	}
-	errno = err;
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	default:
+		errno = ENOENT;
+		break;
+	}
 	return -1;
 }
 
@@ -551,16 +606,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
 {
 	FILETIME mft, aft;
 	int fh, rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
 	/* must have write permission */
-	DWORD attrs = GetFileAttributes(file_name);
+	attrs = GetFileAttributesW(wfilename);
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors here; open() will report them */
-		SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
 	}
 
-	if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+	if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
 		rc = -1;
 		goto revert_attrs;
 	}
@@ -583,7 +642,7 @@ revert_attrs:
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors again */
-		SetFileAttributes(file_name, attrs);
+		SetFileAttributesW(wfilename, attrs);
 	}
 	return rc;
 }
@@ -594,6 +653,18 @@ unsigned int sleep (unsigned int seconds)
 	return 0;
 }
 
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
 int mkstemp(char *template)
 {
 	char *filename = mktemp(template);
@@ -652,17 +723,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
 	return result;
 }
 
-#undef getcwd
 char *mingw_getcwd(char *pointer, int len)
 {
 	int i;
-	char *ret = getcwd(pointer, len);
-	if (!ret)
-		return ret;
+	wchar_t wpointer[MAX_PATH];
+	if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+		return NULL;
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
 	for (i = 0; pointer[i]; i++)
 		if (pointer[i] == '\\')
 			pointer[i] = '/';
-	return ret;
+	return pointer;
 }
 
 #undef getenv
@@ -1495,33 +1567,36 @@ int mingw_rename(const char *pold, const char *pnew)
 {
 	DWORD attrs, gle;
 	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+		return -1;
 
 	/*
 	 * Try native rename() first to get errno right.
 	 * It is based on MoveFile(), which cannot overwrite existing files.
 	 */
-	if (!rename(pold, pnew))
+	if (!_wrename(wpold, wpnew))
 		return 0;
 	if (errno != EEXIST)
 		return -1;
 repeat:
-	if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 		return 0;
 	/* TODO: translate more errors */
 	gle = GetLastError();
 	if (gle == ERROR_ACCESS_DENIED &&
-	    (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
 		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
 			errno = EISDIR;
 			return -1;
 		}
 		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
-		    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
-			if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 				return 0;
 			gle = GetLastError();
 			/* revert file attributes on failure */
-			SetFileAttributes(pnew, attrs);
+			SetFileAttributesW(wpnew, attrs);
 		}
 	}
 	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
@@ -1731,11 +1806,16 @@ void mingw_open_html(const char *unixpath)
 
 int link(const char *oldpath, const char *newpath)
 {
-	typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+	typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
 	static T create_hard_link = NULL;
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
 	if (!create_hard_link) {
 		create_hard_link = (T) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+			GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
 		if (!create_hard_link)
 			create_hard_link = (T)-1;
 	}
@@ -1743,7 +1823,7 @@ int link(const char *oldpath, const char *newpath)
 		errno = ENOSYS;
 		return -1;
 	}
-	if (!create_hard_link(newpath, oldpath, NULL)) {
+	if (!create_hard_link(wnewpath, woldpath, NULL)) {
 		errno = err_win_to_posix(GetLastError());
 		return -1;
 	}
diff --git a/compat/mingw.h b/compat/mingw.h
index ddb228473b..ea8c1f8993 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -182,6 +182,19 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 

From c9733bb460df8fb441641274a0792bcd4b54885f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:01:09 +0100
Subject: [PATCH 3406/3720] Win32: Unicode file name support (dirent)

Changes opendir/readdir to use Windows Unicode APIs and convert between
UTF-8/UTF-16.

Removes parameter checks that are already covered by xutftowcs_path. This
changes detection of ENAMETOOLONG from MAX_PATH - 2 to MAX_PATH (matching
is_dir_empty in mingw.c). If name + "/*" or the resulting absolute path is
too long, FindFirstFile fails and errno is set through err_win_to_posix.

Increases the size of dirent.d_name to accommodate the full
WIN32_FIND_DATA.cFileName converted to UTF-8 (UTF-16 to UTF-8 conversion
may grow by factor three in the worst case).

Signed-off-by: Karsten Blees 
---
 compat/win32/dirent.c | 30 ++++++++++--------------------
 compat/win32/dirent.h |  2 +-
 2 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 82a515c21b..52420ec7d4 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -6,10 +6,10 @@ struct DIR {
 	int dd_stat;          /* 0-based index */
 };
 
-static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
 {
-	/* copy file name from WIN32_FIND_DATA to dirent */
-	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+	/* convert UTF-16 name to UTF-8 */
+	xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
 
 	/* Set file type, based on WIN32_FIND_DATA */
 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -20,25 +20,15 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
 
 DIR *opendir(const char *name)
 {
-	char pattern[MAX_PATH];
-	WIN32_FIND_DATAA fdata;
+	wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
+	WIN32_FIND_DATAW fdata;
 	HANDLE h;
 	int len;
 	DIR *dir;
 
-	/* check that name is not NULL */
-	if (!name) {
-		errno = EINVAL;
+	/* convert name to UTF-16 and check length < MAX_PATH */
+	if ((len = xutftowcs_path(pattern, name)) < 0)
 		return NULL;
-	}
-	/* check that the pattern won't be too long for FindFirstFileA */
-	len = strlen(name);
-	if (len + 2 >= MAX_PATH) {
-		errno = ENAMETOOLONG;
-		return NULL;
-	}
-	/* copy name to temp buffer */
-	memcpy(pattern, name, len + 1);
 
 	/* append optional '/' and wildcard '*' */
 	if (len && !is_dir_sep(pattern[len - 1]))
@@ -47,7 +37,7 @@ DIR *opendir(const char *name)
 	pattern[len] = 0;
 
 	/* open find handle */
-	h = FindFirstFileA(pattern, &fdata);
+	h = FindFirstFileW(pattern, &fdata);
 	if (h == INVALID_HANDLE_VALUE) {
 		DWORD err = GetLastError();
 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
@@ -72,8 +62,8 @@ struct dirent *readdir(DIR *dir)
 	/* if first entry, dirent has already been set up by opendir */
 	if (dir->dd_stat) {
 		/* get next entry and convert from WIN32_FIND_DATA to dirent */
-		WIN32_FIND_DATAA fdata;
-		if (FindNextFileA(dir->dd_handle, &fdata)) {
+		WIN32_FIND_DATAW fdata;
+		if (FindNextFileW(dir->dd_handle, &fdata)) {
 			finddata2dirent(&dir->dd_dir, &fdata);
 		} else {
 			DWORD lasterr = GetLastError();
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 8838cd61fc..058207e4bf 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,7 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
-	char d_name[MAX_PATH];     /* file name */
+	char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
 };
 
 DIR *opendir(const char *dirname);

From b74f73aed171ada4234ee40faf5281a4cff77be5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 4 Feb 2012 21:54:36 +0100
Subject: [PATCH 3407/3720] Unicode file name support (gitk and git-gui)

Assumes file names in git tree objects are UTF-8 encoded.

On most unix systems, the system encoding (and thus the TCL system
encoding) will be UTF-8, so file names will be displayed correctly.

On Windows, it is impossible to set the system encoding to UTF-8. Changing
the TCL system encoding (via 'encoding system ...', e.g. in the startup
code) is explicitly discouraged by the TCL docs.

Change gitk and git-gui functions dealing with file names to always convert
from and to UTF-8.

Signed-off-by: Karsten Blees 
---
 git-gui/git-gui.sh      | 11 +++++++----
 git-gui/lib/browser.tcl |  2 +-
 git-gui/lib/index.tcl   |  6 +++---
 gitk-git/gitk           | 16 ++++++++--------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index a59020bcc5..e5038ddd12 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -533,6 +533,9 @@ proc git {args} {
 
 	_trace_exec [concat $opt $cmdp $args]
 	set result [eval exec $opt $cmdp $args]
+	if {[encoding system] != "utf-8"} {
+		set result [encoding convertfrom utf-8 [encoding convertto $result]]
+	}
 	if {$::_trace} {
 		puts stderr "< $result"
 	}
@@ -1087,7 +1090,7 @@ git-version proc _parse_config {arr_name args} {
 				[list git_read config] \
 				$args \
 				[list --null --list]]
-			fconfigure $fd_rc -translation binary
+			fconfigure $fd_rc -translation binary -encoding utf-8
 			set buf [read $fd_rc]
 			close $fd_rc
 		}
@@ -1652,7 +1655,7 @@ proc read_diff_index {fd after} {
 		set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			[lindex $i 4]? \
 			[list [lindex $i 0] [lindex $i 2]] \
 			[list]
@@ -1685,7 +1688,7 @@ proc read_diff_files {fd after} {
 		set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			?[lindex $i 4] \
 			[list] \
 			[list [lindex $i 0] [lindex $i 2]]
@@ -1708,7 +1711,7 @@ proc read_ls_others {fd after} {
 	set pck [split $buf_rlo "\0"]
 	set buf_rlo [lindex $pck end]
 	foreach p [lrange $pck 0 end-1] {
-		set p [encoding convertfrom $p]
+		set p [encoding convertfrom utf-8 $p]
 		if {[string index $p end] eq {/}} {
 			set p [string range $p 0 end-1]
 		}
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 4fca8fb13c..555db896f4 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary
+	fconfigure $fd -blocking 0 -translation binary -encoding utf-8
 	fileevent $fd readable [cb _read $fd]
 }
 
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdde21..6ca0a6e369 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -115,7 +115,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
 		set info [lindex $s 2]
 		if {$info eq {}} continue
 
-		puts -nonewline $fd "$info\t[encoding convertto $path]\0"
+		puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -186,7 +186,7 @@ proc write_update_index {fd pathList totalCnt batch after} {
 		?M {set new M_}
 		?? {continue}
 		}
-		puts -nonewline $fd "[encoding convertto $path]\0"
+		puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -247,7 +247,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
 		?M -
 		?T -
 		?D {
-			puts -nonewline $fd "[encoding convertto $path]\0"
+			puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 			display_file $path ?_
 		}
 		}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 16ff52a2c1..59693c0005 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7329,7 +7329,7 @@ proc gettreeline {gtf id} {
 	if {[string index $fname 0] eq "\""} {
 	    set fname [lindex $fname 0]
 	}
-	set fname [encoding convertfrom $fname]
+	set fname [encoding convertfrom utf-8 $fname]
 	lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -7551,7 +7551,7 @@ proc gettreediffline {gdtf ids} {
 	    if {[string index $file 0] eq "\""} {
 		set file [lindex $file 0]
 	    }
-	    set file [encoding convertfrom $file]
+	    set file [encoding convertfrom utf-8 $file]
 	    if {$file ne [lindex $treediff end]} {
 		lappend treediff $file
 		lappend sublist $file
@@ -7700,7 +7700,7 @@ proc makediffhdr {fname ids} {
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -7734,7 +7734,7 @@ proc getblobdiffline {bdf ids} {
 	}
 	if {![string compare -length 5 "diff " $line]} {
 	    if {![regexp {^diff (--cc|--git) } $line m type]} {
-		set line [encoding convertfrom $line]
+		set line [encoding convertfrom utf-8 $line]
 		$ctext insert end "$line\n" hunksep
 		continue
 	    }
@@ -7781,7 +7781,7 @@ proc getblobdiffline {bdf ids} {
 	    makediffhdr $fname $ids
 
 	} elseif {![string compare -length 16 "* Unmerged path " $line]} {
-	    set fname [encoding convertfrom [string range $line 16 end]]
+	    set fname [encoding convertfrom utf-8 [string range $line 16 end]]
 	    $ctext insert end "\n"
 	    set curdiffstart [$ctext index "end - 1c"]
 	    lappend ctext_file_names $fname
@@ -7836,7 +7836,7 @@ proc getblobdiffline {bdf ids} {
 		if {[string index $fname 0] eq "\""} {
 		    set fname [lindex $fname 0]
 		}
-		set fname [encoding convertfrom $fname]
+		set fname [encoding convertfrom utf-8 $fname]
 		set i [lsearch -exact $treediffs($ids) $fname]
 		if {$i >= 0} {
 		    setinlist difffilestart $i $curdiffstart
@@ -7855,7 +7855,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
-	    set line [encoding convertfrom $line]
+	    set line [encoding convertfrom utf-8 $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {
@@ -11521,7 +11521,7 @@ proc cache_gitattr {attr pathlist} {
 	    foreach row [split $rlist "\n"] {
 		if {[regexp "(.*): $attr: (.*)" $row m path value]} {
 		    if {[string index $path 0] eq "\""} {
-			set path [encoding convertfrom [lindex $path 0]]
+			set path [encoding convertfrom utf-8 [lindex $path 0]]
 		    }
 		    set path_attr_cache($attr,$path) $value
 		}

From 1cafcd6bce7816756affe0163feb43a7c379cc86 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:27:53 +0100
Subject: [PATCH 3408/3720] Win32: Unicode arguments (outgoing)

Convert command line arguments from UTF-8 to UTF-16 when creating other
processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 5d5f30bd2c..de0a55fe84 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -955,9 +955,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFO si;
+	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
 	struct strbuf envblk, args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
 	unsigned flags;
 	BOOL ret;
 
@@ -993,6 +994,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	si.hStdOutput = winansi_get_osfhandle(fhout);
 	si.hStdError = winansi_get_osfhandle(fherr);
 
+	if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
 	if (prepend_cmd) {
@@ -1010,6 +1016,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			free(quoted);
 	}
 
+	wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
@@ -1031,12 +1041,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	}
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir, &si, &pi);
+	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
 	if (env)
 		strbuf_release(&envblk);
-	strbuf_release(&args);
+	free(wargs);
 
 	if (!ret) {
 		errno = ENOENT;

From dbef50ef29538c1d0cde933f8d16904599026f83 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:28:27 +0100
Subject: [PATCH 3409/3720] Win32: Unicode arguments (incoming)

Convert command line arguments from UTF-16 to UTF-8 on startup.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index de0a55fe84..428c056009 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2040,10 +2040,41 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
  */
 int _CRT_glob = 0;
 
+typedef struct {
+	int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+		_startupinfo *si);
+
 void mingw_startup()
 {
-	/* copy executable name to argv[0] */
-	__argv[0] = xstrdup(_pgmptr);
+	int i, len, maxlen, argc;
+	char *buffer;
+	wchar_t **wenv, **wargv;
+	_startupinfo si;
+
+	/* get wide char arguments and environment */
+	si.newmode = 0;
+	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(_wpgmptr);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = xmalloc(maxlen);
+
+	/* convert command line arguments and environment to UTF-8 */
+	len = xwcstoutf(buffer, _wpgmptr, maxlen);
+	__argv[0] = xmemdupz(buffer, len);
+	for (i = 1; i < argc; i++) {
+		len = xwcstoutf(buffer, wargv[i], maxlen);
+		__argv[i] = xmemdupz(buffer, len);
+	}
+	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);

From 1105fe1094e7bc14b150f06e7d7a3d9e3220a929 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:17:49 +0100
Subject: [PATCH 3410/3720] Win32: sync Unicode console output and file system

Use the same Unicode conversion functions for file names and console
conversions so that the file system and console output are in sync when
checking out legacy encoded repositories (i.e. with invalid UTF-8 file
names).

Signed-off-by: Karsten Blees 
---
 compat/winansi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a3e4d88295..9f95954390 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -120,8 +120,7 @@ static void write_console(unsigned char *str, size_t len)
 	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
 
 	/* convert utf-8 to utf-16 */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
-			ARRAY_SIZE(wbuf));
+	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);

From a635fdacfe5e2202d0bd55033874ea8e029288e9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:07:46 +0100
Subject: [PATCH 3411/3720] Win32: Unicode environment (outgoing)

Convert environment from UTF-8 to UTF-16 when creating other processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 428c056009..d78ac239e0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -957,9 +957,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 {
 	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
-	struct strbuf envblk, args;
-	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
-	unsigned flags;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 
 	/* Determine whether or not we are associated to a console */
@@ -976,7 +976,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * instead of CREATE_NO_WINDOW to make ssh
 		 * recognize that it has no console.
 		 */
-		flags = DETACHED_PROCESS;
+		flags |= DETACHED_PROCESS;
 	} else {
 		/* There is already a console. If we specified
 		 * DETACHED_PROCESS here, too, Windows would
@@ -984,7 +984,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * The same is true for CREATE_NO_WINDOW.
 		 * Go figure!
 		 */
-		flags = 0;
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
@@ -1023,6 +1022,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
+		int size = 0, wenvsz = 0, wenvpos = 0;
 
 		for (e = env; *e; e++)
 			count++;
@@ -1032,20 +1032,22 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
 		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
 
-		strbuf_init(&envblk, 0);
+		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
-			strbuf_addstr(&envblk, *e);
-			strbuf_addch(&envblk, '\0');
+			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
 		}
+		/* add final \0 terminator */
+		wenvblk[wenvpos] = 0;
 		free(sorted_env);
 	}
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
+		wenvblk, dir ? wdir : NULL, &si, &pi);
 
-	if (env)
-		strbuf_release(&envblk);
+	free(wenvblk);
 	free(wargs);
 
 	if (!ret) {

From 8f426162ffd068a10f5662d87c3a78ee080e9ca7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 25 Apr 2011 23:32:27 +0100
Subject: [PATCH 3412/3720] Win32: Unicode environment (incoming)

Convert environment from UTF-16 to UTF-8 on startup.

No changes to getenv() are necessary, as the MSVCRT version is implemented
on top of char **environ.

However, putenv / _wputenv from MSVCRT no longer work, for two reasons:
1. they try to keep environ, _wenviron and the Win32 process environment
in sync, using the default system encoding instead of UTF-8 to convert
between charsets
2. msysgit and MSVCRT use different allocators, memory allocated in git
cannot be freed by the CRT and vice versa

Implement mingw_putenv using the env_setenv helper function from the
environment merge code.

Note that in case of memory allocation failure, putenv now dies with error
message (due to xrealloc) instead of failing with ENOMEM. As git assumes
setenv / putenv to always succeed, this prevents it from continuing with
incorrect settings.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index d78ac239e0..fe1d0de81f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1282,6 +1282,12 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -2064,6 +2070,11 @@ void mingw_startup()
 	maxlen = wcslen(_wpgmptr);
 	for (i = 1; i < argc; i++)
 		maxlen = max(maxlen, wcslen(wargv[i]));
+	for (i = 0; wenv[i]; i++)
+		maxlen = max(maxlen, wcslen(wenv[i]));
+
+	/* nedmalloc can't free CRT memory, allocate resizable environment list */
+	environ = xcalloc(i + 1, sizeof(char*));
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2076,6 +2087,10 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wargv[i], maxlen);
 		__argv[i] = xmemdupz(buffer, len);
 	}
+	for (i = 0; wenv[i]; i++) {
+		len = xwcstoutf(buffer, wenv[i], maxlen);
+		environ[i] = xmemdupz(buffer, len);
+	}
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
diff --git a/compat/mingw.h b/compat/mingw.h
index ea8c1f8993..af1574c435 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -200,6 +200,8 @@ char *mingw_getcwd(char *pointer, int len);
 
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
+int mingw_putenv(const char *namevalue);
+#define putenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 58430e14d63c300b9720cc3c510673b6a25e16f2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 20 Aug 2011 14:27:02 +0200
Subject: [PATCH 3413/3720] MinGW: disable legacy encoding tests

On Windows, all native APIs are Unicode-based. It is impossible to pass
legacy encoded byte arrays to a process via command line or environment
variables. Disable the tests that try to do so.

In t3901, most tests still work if we don't mess up the repository encoding
in setup, so don't switch to ISO-8859-1 on MinGW.

Note that i18n tests that do their encoding tricks via encoded files (such
as t3900) are not affected by this.

Signed-off-by: Karsten Blees 
---
 t/t3901-i18n-patch.sh | 19 +++++++++++--------
 t/t4201-shortlog.sh   |  6 +++---
 t/t8005-blame-i18n.sh |  8 ++++----
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 31a5770b34..55c8a2f576 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -54,10 +54,13 @@ test_expect_success setup '
 	git add yours &&
 	git commit -s -m "Second on side" &&
 
-	# the second one on the side branch is ISO-8859-1
-	git config i18n.commitencoding ISO8859-1 &&
-	# use author and committer name in ISO-8859-1 to match it.
-	. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+	if test_have_prereq NOT_MINGW
+	then
+		# the second one on the side branch is ISO-8859-1
+		git config i18n.commitencoding ISO8859-1 &&
+		# use author and committer name in ISO-8859-1 to match it.
+		. "$TEST_DIRECTORY"/t3901-8859-1.txt
+	fi &&
 	test_tick &&
 	echo Yet another >theirs &&
 	git add theirs &&
@@ -119,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
 	check_encoding 2
 '
 
-test_expect_success 'rebase (L/L)' '
+test_expect_success NOT_MINGW 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
 	git config i18n.commitencoding ISO8859-1 &&
 	git config i18n.logoutputencoding ISO8859-1 &&
@@ -131,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 	check_encoding 2 8859
 '
 
-test_expect_success 'rebase (L/U)' '
+test_expect_success NOT_MINGW 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
 	git config i18n.commitencoding ISO8859-1 &&
@@ -159,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/L)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
 	git config i18n.commitencoding ISO8859-1 &&
@@ -189,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/U)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6872ba1a42..48963811bf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
 	test_cmp expect log.predictable
 '
 
-test_expect_success 'shortlog wrapping' '
+test_expect_success NOT_MINGW 'shortlog wrapping' '
 	cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
 	test_cmp expect out
 '
 
-test_expect_success 'shortlog from non-git directory' '
+test_expect_success NOT_MINGW 'shortlog from non-git directory' '
 	git log HEAD >log &&
 	GIT_DIR=non-existing git shortlog -w out &&
 	test_cmp expect out
@@ -135,7 +135,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success 'shortlog encoding' '
+test_expect_success NOT_MINGW 'shortlog encoding' '
 	git reset --hard "$commit" &&
 	git config --unset i18n.commitencoding &&
 	echo 2 > a1 &&
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index cb390559f9..a6e73d0635 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.commitencoding' '
 	git blame --incremental file | \
 		egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.logoutputencoding' '
 	git config i18n.logoutputencoding eucJP &&
 	git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=UTF-8' '
 	git blame --incremental --encoding=UTF-8 file | \
 		egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=none' '
 	git blame --incremental --encoding=none file | \
 		egrep "^(author|summary) " > actual &&

From 0839172027e0ee44f2e3c51ea3311be37a10fc65 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:29:40 +0100
Subject: [PATCH 3414/3720] Win32: fix environment memory leaks

All functions that modify the environment have memory leaks.

Disable gitunsetenv in the Makefile and use env_setenv (via mingw_putenv)
instead (this frees removed environment entries).

Move xstrdup from env_setenv to make_augmented_environ, so that
mingw_putenv no longer copies the environment entries (according to POSIX
[1], "the string [...] shall become part of the environment"). This also
fixes the memory leak in gitsetenv, which expects a POSIX compliant putenv.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html

Note: This patch depends on taking control of char **environ and having
our own mingw_putenv (both introduced in "Win32: Unicode environment
(incoming)").

Signed-off-by: Karsten Blees 
---
 Makefile       |  2 --
 compat/mingw.c | 10 ++++++----
 compat/mingw.h |  1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index c82f297f0f..77111b1f46 100644
--- a/Makefile
+++ b/Makefile
@@ -1160,7 +1160,6 @@ ifeq ($(uname_S),Windows)
 	NO_IPV6 = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
@@ -1257,7 +1256,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SYMLINK_HEAD = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index fe1d0de81f..bbd35d8bd4 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1255,14 +1255,14 @@ static char **env_setenv(char **env, const char *name)
 			for (i = 0; env[i]; i++)
 				;
 			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 			env[i+1] = NULL;
 		}
 	}
 	else {
 		free(env[i]);
 		if (*eq)
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 		else
 			for (; env[i]; i++)
 				env[i] = env[i+1];
@@ -1277,8 +1277,10 @@ char **make_augmented_environ(const char *const *vars)
 {
 	char **env = copy_environ();
 
-	while (*vars)
-		env = env_setenv(env, *vars++);
+	while (*vars) {
+		const char *v = *vars++;
+		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+	}
 	return env;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index af1574c435..ba21474515 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -202,6 +202,7 @@ char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 int mingw_putenv(const char *namevalue);
 #define putenv mingw_putenv
+#define unsetenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 98bcd7008e1946c8551dea32901e5dd8446947bd Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 23:42:09 +0100
Subject: [PATCH 3415/3720] Win32: unify environment case-sensitivity

The environment on Windows is case-insensitive. Some environment functions
(such as unsetenv and make_augmented_environ) have always used case-
sensitive comparisons instead, while others (getenv, putenv, sorting in
spawn*) were case-insensitive.

Prevent potential inconsistencies by using case-insensitive comparison in
lookup_env (used by putenv, unsetenv and make_augmented_environ).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bbd35d8bd4..bef2f3314e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1234,8 +1234,7 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 	int i;
 
 	for (i = 0; env[i]; i++) {
-		if (0 == strncmp(env[i], name, nmln)
-		    && '=' == env[i][nmln])
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
 			/* matches */
 			return i;
 	}

From 5fd9cab8fff84472733c4956a25c7b47745de3f7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:33:17 +0100
Subject: [PATCH 3416/3720] Win32: simplify internal mingw_spawn* APIs

The only public spawn function that needs to tweak the environment is
mingw_spawnvpe (called from start_command). Nevertheless, all internal
spawn* functions take an env parameter and needlessly pass the global
char **environ around. Remove the env parameter where it's not needed.

This removes the internal mingw_execve abstraction, which is no longer
needed.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bef2f3314e..311a1832d0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1077,10 +1077,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-			   int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -1122,7 +1121,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 	return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
 	const char *interpr = parse_interpreter(cmd);
 	char **path;
@@ -1140,7 +1139,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 		argv2 = xmalloc(sizeof(*argv) * (argc+1));
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-		pid = mingw_spawnve(prog, argv2, env, 1);
+		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -1155,13 +1154,13 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 	return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+void mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
-	if (!try_shell_exec(cmd, argv, (char **)env)) {
+	if (!try_shell_exec(cmd, argv)) {
 		int pid, status;
 
-		pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
 			return;
 		if (waitpid(pid, &status, 0) < 0)
@@ -1176,7 +1175,7 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	char *prog = path_lookup(cmd, path, 0);
 
 	if (prog) {
-		mingw_execve(prog, argv, environ);
+		mingw_execv(prog, argv);
 		free(prog);
 	} else
 		errno = ENOENT;
@@ -1184,11 +1183,6 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	free_path_split(path);
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
-{
-	mingw_execve(cmd, argv, environ);
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
 	if (pid > 0 && sig == SIGTERM) {

From 17bc7bc5f6b0bdba1e193d681c46dae4b3909fef Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:05:04 +0100
Subject: [PATCH 3417/3720] Win32: move environment functions

Move environment helper functions up so that they can be reused by
mingw_getenv and mingw_spawnve_fd in subsequent patches.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 106 ++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 311a1832d0..0c406669df 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,6 +737,53 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
+static int env_compare(const void *a, const void *b)
+{
+	char *const *ea = a;
+	char *const *eb = b;
+	return strcasecmp(*ea, *eb);
+}
+
+static int lookup_env(char **env, const char *name, size_t nmln)
+{
+	int i;
+
+	for (i = 0; env[i]; i++) {
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
+			/* matches */
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * If name contains '=', then sets the variable, otherwise it unsets it
+ */
+static char **env_setenv(char **env, const char *name)
+{
+	char *eq = strchrnul(name, '=');
+	int i = lookup_env(env, name, eq-name);
+
+	if (i < 0) {
+		if (*eq) {
+			for (i = 0; env[i]; i++)
+				;
+			env = xrealloc(env, (i+2)*sizeof(*env));
+			env[i] = (char*) name;
+			env[i+1] = NULL;
+		}
+	}
+	else {
+		free(env[i]);
+		if (*eq)
+			env[i] = (char*) name;
+		else
+			for (; env[i]; i++)
+				env[i] = env[i+1];
+	}
+	return env;
+}
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -754,6 +801,12 @@ char *mingw_getenv(const char *name)
 	return result;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -936,13 +989,6 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
-static int env_compare(const void *a, const void *b)
-{
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
-}
-
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1223,46 +1269,6 @@ void free_environ(char **env)
 	free(env);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
-{
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
-	}
-	return -1;
-}
-
-/*
- * If name contains '=', then sets the variable, otherwise it unsets it
- */
-static char **env_setenv(char **env, const char *name)
-{
-	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
-
-	if (i < 0) {
-		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
-		}
-	}
-	else {
-		free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-	}
-	return env;
-}
-
 /*
  * Copies global environ and adjusts variables as specified by vars.
  */
@@ -1277,12 +1283,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-int mingw_putenv(const char *namevalue)
-{
-	environ = env_setenv(environ, namevalue);
-	return 0;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 3f5e24c74b28e8774fd96e4cc3acde71106e9fc4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Wed, 5 Oct 2011 22:01:46 +0200
Subject: [PATCH 3418/3720] Win32: unify environment function names

Environment helper functions use random naming ('env' prefix or suffix or
both, with or without '_'). Change to POSIX naming scheme ('env' suffix,
no '_').

Env_setenv has more in common with putenv than setenv. Change to do_putenv.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0c406669df..e5d8c6a438 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,14 +737,14 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int env_compare(const void *a, const void *b)
+static int compareenv(const void *a, const void *b)
 {
 	char *const *ea = a;
 	char *const *eb = b;
 	return strcasecmp(*ea, *eb);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
+static int lookupenv(char **env, const char *name, size_t nmln)
 {
 	int i;
 
@@ -759,10 +759,10 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **env_setenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name)
 {
 	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
+	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
@@ -803,7 +803,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = env_setenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue);
 	return 0;
 }
 
@@ -1076,7 +1076,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		/* environment must be sorted */
 		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
 
 		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
@@ -1278,7 +1278,7 @@ char **make_augmented_environ(const char *const *vars)
 
 	while (*vars) {
 		const char *v = *vars++;
-		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
 	}
 	return env;
 }

From 93c712cdb558c0007ec9690d2ea5c2dcfe70afb1 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:31:57 +0100
Subject: [PATCH 3419/3720] Win32: factor out environment block creation

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 55 +++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e5d8c6a438..be381573f1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -989,6 +989,36 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
+/*
+ * Create environment block suitable for CreateProcess.
+ */
+static wchar_t *make_environment_block(char **env)
+{
+	wchar_t *wenvblk = NULL;
+	int count = 0;
+	char **e, **tmpenv;
+	int size = 0, wenvsz = 0, wenvpos = 0;
+
+	for (e = env; *e; e++)
+		count++;
+
+	/* environment must be sorted */
+	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+
+	/* create environment block from temporary environment */
+	for (e = tmpenv; *e; e++) {
+		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+	}
+	/* add final \0 terminator */
+	wenvblk[wenvpos] = 0;
+	free(tmpenv);
+	return wenvblk;
+}
+
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1065,29 +1095,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env) {
-		int count = 0;
-		char **e, **sorted_env;
-		int size = 0, wenvsz = 0, wenvpos = 0;
-
-		for (e = env; *e; e++)
-			count++;
-
-		/* environment must be sorted */
-		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
-		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
-
-		/* create environment block from temporary environment */
-		for (e = sorted_env; *e; e++) {
-			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
-			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
-		}
-		/* add final \0 terminator */
-		wenvblk[wenvpos] = 0;
-		free(sorted_env);
-	}
+	if (env)
+		wenvblk = make_environment_block(env);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,

From b2c76b0bc90e2f1b93cacaa36ea4a922b7dc1314 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:57:14 +0100
Subject: [PATCH 3420/3720] Win32: don't copy the environment twice when
 spawning child processes

When spawning child processes via start_command(), the environment and all
environment entries are copied twice. First by make_augmented_environ /
copy_environ to merge with child_process.env. Then a second time by
make_environment_block to create a sorted environment block string as
required by CreateProcess.

Move the merge logic to make_environment_block so that we only need to copy
the environment once. This changes semantics of the env parameter: it now
expects a delta (such as child_process.env) rather than a full environment.
This is not a problem as the parameter is only used by start_command()
(all other callers previously passed char **environ, and now pass NULL).

The merge logic no longer xstrdup()s the environment strings, so do_putenv
must not free them. Add a parameter to distinguish this from normal putenv.

Remove the now unused make_augmented_environ / free_environ API.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 74 ++++++++++++++++----------------------------------
 compat/mingw.h |  6 ----
 run-command.c  | 10 ++-----
 3 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index be381573f1..9a0b39a47e 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -759,7 +759,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **do_putenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
@@ -774,7 +774,8 @@ static char **do_putenv(char **env, const char *name)
 		}
 	}
 	else {
-		free(env[i]);
+		if (free_old)
+			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
 		else
@@ -803,7 +804,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue, 1);
 	return 0;
 }
 
@@ -990,21 +991,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 }
 
 /*
- * Create environment block suitable for CreateProcess.
+ * Create environment block suitable for CreateProcess. Merges current
+ * process environment and the supplied environment changes.
  */
-static wchar_t *make_environment_block(char **env)
+static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
 	int count = 0;
 	char **e, **tmpenv;
 	int size = 0, wenvsz = 0, wenvpos = 0;
 
-	for (e = env; *e; e++)
+	while (environ[count])
 		count++;
 
-	/* environment must be sorted */
+	/* copy the environment */
 	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+
+	/* merge supplied environment changes into the temporary environment */
+	for (e = deltaenv; e && *e; e++)
+		tmpenv = do_putenv(tmpenv, *e, 0);
+
+	/* environment must be sorted */
+	for (count = 0; tmpenv[count]; )
+		count++;
 	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
 
 	/* create environment block from temporary environment */
@@ -1027,7 +1037,7 @@ struct pinfo_t {
 struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
-static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
@@ -1095,8 +1105,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env)
-		wenvblk = make_environment_block(env);
+	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1134,10 +1143,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
 static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 		     const char *dir,
 		     int fhin, int fhout, int fherr)
 {
@@ -1161,14 +1170,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 				pid = -1;
 			}
 			else {
-				pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
 						       fhin, fhout, fherr);
 				free(iprog);
 			}
 			argv[0] = argv0;
 		}
 		else
-			pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
 					       fhin, fhout, fherr);
 		free(prog);
 	}
@@ -1257,41 +1266,6 @@ int mingw_kill(pid_t pid, int sig)
 	return -1;
 }
 
-static char **copy_environ(void)
-{
-	char **env;
-	int i = 0;
-	while (environ[i])
-		i++;
-	env = xmalloc((i+1)*sizeof(*env));
-	for (i = 0; environ[i]; i++)
-		env[i] = xstrdup(environ[i]);
-	env[i] = NULL;
-	return env;
-}
-
-void free_environ(char **env)
-{
-	int i;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-/*
- * Copies global environ and adjusts variables as specified by vars.
- */
-char **make_augmented_environ(const char *const *vars)
-{
-	char **env = copy_environ();
-
-	while (*vars) {
-		const char *v = *vars++;
-		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
-	}
-	return env;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
diff --git a/compat/mingw.h b/compat/mingw.h
index ba21474515..04b6523255 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -335,12 +335,6 @@ void mingw_open_html(const char *path);
 void mingw_mark_as_git_dir(const char *dir);
 #define mark_as_git_dir mingw_mark_as_git_dir
 
-/*
- * helpers
- */
-
-char **make_augmented_environ(const char *const *vars);
-void free_environ(char **env);
 
 /**
  * Converts UTF-8 encoded string to UTF-16LE.
diff --git a/run-command.c b/run-command.c
index 1db8abf984..6d0dc3da91 100644
--- a/run-command.c
+++ b/run-command.c
@@ -381,7 +381,6 @@ fail_pipe:
 {
 	int fhin = 0, fhout = 1, fherr = 2;
 	const char **sargv = cmd->argv;
-	char **env = environ;
 
 	if (cmd->no_stdin)
 		fhin = open("/dev/null", O_RDWR);
@@ -406,25 +405,20 @@ fail_pipe:
 	else if (cmd->out > 1)
 		fhout = dup(cmd->out);
 
-	if (cmd->env)
-		env = make_augmented_environ(cmd->env);
-
 	if (cmd->git_cmd) {
 		cmd->argv = prepare_git_cmd(cmd->argv);
 	} else if (cmd->use_shell) {
 		cmd->argv = prepare_shell_cmd(cmd->argv);
 	}
 
-	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
-				  fhin, fhout, fherr);
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
 	failed_errno = errno;
 	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 		error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 	if (cmd->clean_on_exit && cmd->pid >= 0)
 		mark_child_for_cleanup(cmd->pid);
 
-	if (cmd->env)
-		free_environ(env);
 	if (cmd->git_cmd)
 		free(cmd->argv);
 

From 1a44adcd0f6130eb6939a0003ac510ab80853008 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:00:35 +0100
Subject: [PATCH 3421/3720] Win32: reduce environment array reallocations

Move environment array reallocation from do_putenv to the respective
callers. Keep track of the environment size in a global variable. Use
ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a
sufficiently sized environment array in make_environment_block to prevent
reallocations.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 60 ++++++++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9a0b39a47e..2d984bd8d3 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -758,19 +758,19 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
+ * Size includes the terminating NULL. Env must have room for size + 1 entries
+ * (in case of insert). Returns the new size. Optionally frees removed entries.
  */
-static char **do_putenv(char **env, const char *name, int free_old)
+static int do_putenv(char **env, const char *name, int size, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
+			env[size - 1] = (char*) name;
+			env[size] = NULL;
+			size++;
 		}
 	}
 	else {
@@ -778,13 +778,20 @@ static char **do_putenv(char **env, const char *name, int free_old)
 			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
-		else
+		else {
 			for (; env[i]; i++)
 				env[i] = env[i+1];
+			size--;
+		}
 	}
-	return env;
+	return size;
 }
 
+/* used number of elements of environ array, including terminating NULL */
+static int environ_size = 0;
+/* allocated size of environ array, in bytes */
+static int environ_alloc = 0;
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -804,7 +811,8 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue, 1);
+	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
+	environ_size = do_putenv(environ, namevalue, environ_size, 1);
 	return 0;
 }
 
@@ -997,31 +1005,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
-	int count = 0;
-	char **e, **tmpenv;
-	int size = 0, wenvsz = 0, wenvpos = 0;
+	char **tmpenv;
+	int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
 
-	while (environ[count])
-		count++;
+	while (deltaenv && deltaenv[i])
+		i++;
 
-	/* copy the environment */
-	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+	/* copy the environment, leaving space for changes */
+	tmpenv = xmalloc((size + i) * sizeof(char*));
+	memcpy(tmpenv, environ, size * sizeof(char*));
 
 	/* merge supplied environment changes into the temporary environment */
-	for (e = deltaenv; e && *e; e++)
-		tmpenv = do_putenv(tmpenv, *e, 0);
+	for (i = 0; deltaenv && deltaenv[i]; i++)
+		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
 	/* environment must be sorted */
-	for (count = 0; tmpenv[count]; )
-		count++;
-	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
 
 	/* create environment block from temporary environment */
-	for (e = tmpenv; *e; e++) {
-		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+	for (i = 0; tmpenv[i]; i++) {
+		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
 		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+		wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
 	}
 	/* add final \0 terminator */
 	wenvblk[wenvpos] = 0;
@@ -2052,7 +2057,9 @@ void mingw_startup()
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
 	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = xcalloc(i + 1, sizeof(char*));
+	environ = NULL;
+	environ_size = i + 1;
+	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2069,6 +2076,7 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wenv[i], maxlen);
 		environ[i] = xmemdupz(buffer, len);
 	}
+	environ[i] = NULL;
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */

From 7a70420455badf1eea2e7cf3712639f4d6ad4ce9 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:29:04 +0100
Subject: [PATCH 3422/3720] Win32: use low-level memory allocation during
 initialization

As of d41489a6 "Add more large blob test cases", git's high-level memory
allocation functions (xmalloc, xmemdupz etc.) access the environment to
simulate limited memory in tests (see 'getenv("GIT_ALLOC_LIMIT")' in
memory_limit_check()). These functions should not be used before the
environment is fully initialized (particularly not to initialize the
environment itself).

The current solution ('environ = NULL; ALLOC_GROW(environ...)') only works
because MSVCRT's getenv() reinitializes environ when it is NULL (i.e. it
leaves us with two sets of unusabe (non-UTF-8) and unfreeable (CRT-
allocated) environments).

Add our own set of malloc-or-die functions to be used in startup code.

Also check the result of __wgetmainargs, which may fail if there's not
enough memory for wide-char arguments and environment.

This patch is in preparation of the sorted environment feature, which
completely replaces MSVCRT's getenv() implementation.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 52 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 2d984bd8d3..f6934f7b79 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2038,16 +2038,37 @@ typedef struct {
 extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
 		_startupinfo *si);
 
+static NORETURN void die_startup()
+{
+	fputs("fatal: not enough memory for initialization", stderr);
+	exit(128);
+}
+
+static void *malloc_startup(size_t size)
+{
+	void *result = malloc(size);
+	if (!result)
+		die_startup();
+	return result;
+}
+
+static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
+{
+	len = xwcstoutf(buffer, wcs, len) + 1;
+	return memcpy(malloc_startup(len), buffer, len);
+}
+
 void mingw_startup()
 {
-	int i, len, maxlen, argc;
+	int i, maxlen, argc;
 	char *buffer;
 	wchar_t **wenv, **wargv;
 	_startupinfo si;
 
 	/* get wide char arguments and environment */
 	si.newmode = 0;
-	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+	if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
+		die_startup();
 
 	/* determine size of argv and environ conversion buffer */
 	maxlen = wcslen(_wpgmptr);
@@ -2056,26 +2077,25 @@ void mingw_startup()
 	for (i = 0; wenv[i]; i++)
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
-	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = NULL;
+	/*
+	 * nedmalloc can't free CRT memory, allocate resizable environment
+	 * list. Note that xmalloc / xmemdupz etc. call getenv, so we cannot
+	 * use it while initializing the environment itself.
+	 */
 	environ_size = i + 1;
-	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
+	environ_alloc = alloc_nr(environ_size * sizeof(char*));
+	environ = malloc_startup(environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
-	buffer = xmalloc(maxlen);
+	buffer = malloc_startup(maxlen);
 
 	/* convert command line arguments and environment to UTF-8 */
-	len = xwcstoutf(buffer, _wpgmptr, maxlen);
-	__argv[0] = xmemdupz(buffer, len);
-	for (i = 1; i < argc; i++) {
-		len = xwcstoutf(buffer, wargv[i], maxlen);
-		__argv[i] = xmemdupz(buffer, len);
-	}
-	for (i = 0; wenv[i]; i++) {
-		len = xwcstoutf(buffer, wenv[i], maxlen);
-		environ[i] = xmemdupz(buffer, len);
-	}
+	__argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
+	for (i = 1; i < argc; i++)
+		__argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+	for (i = 0; wenv[i]; i++)
+		environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen);
 	environ[i] = NULL;
 	free(buffer);
 

From 255e00b146502151552840afd296a982dd4238b6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:30:02 +0100
Subject: [PATCH 3423/3720] Win32: keep the environment sorted

The Windows environment is sorted, keep it that way for O(log n)
environment access.

Change compareenv to compare only the keys, so that it can be used to
find an entry irrespective of the value.

Change lookupenv to binary seach for an entry. Return one's complement of
the insert position if not found (libc's bsearch returns NULL).

Replace MSVCRT's getenv with a minimal do_getenv based on the binary search
function.

Change do_putenv to insert new entries at the correct position. Simplify
the function by swapping if conditions and using memmove instead of for
loops.

Move qsort from make_environment_block to mingw_startup. We still need to
sort on startup to make sure that the environment is sorted according to
our compareenv function (while Win32 / CreateProcess requires the
environment block to be sorted case-insensitively, CreateProcess currently
doesn't enforce this, and some applications such as bash just don't care).

Note that environment functions are _not_ thread-safe and are not required
to be so by POSIX, the application is responsible for synchronizing access
to the environment. MSVCRT's getenv and our new getenv implementation are
better than that in that they are thread-safe with respect to other getenv
calls as long as the environment is not modified. Git's indiscriminate use
of getenv in background threads currently requires this property.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 98 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 62 insertions(+), 36 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index f6934f7b79..67c9e9c4f6 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,23 +737,42 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int compareenv(const void *a, const void *b)
+/*
+ * Compare environment entries by key (i.e. stopping at '=' or '\0').
+ */
+static int compareenv(const void *v1, const void *v2)
 {
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
+	const char *e1 = *(const char**)v1;
+	const char *e2 = *(const char**)v2;
+
+	for (;;) {
+		int c1 = *e1++;
+		int c2 = *e2++;
+		c1 = (c1 == '=') ? 0 : tolower(c1);
+		c2 = (c2 == '=') ? 0 : tolower(c2);
+		if (c1 > c2)
+			return 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 == 0)
+			return 0;
+	}
 }
 
-static int lookupenv(char **env, const char *name, size_t nmln)
+static int bsearchenv(char **env, const char *name, size_t size)
 {
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
+	unsigned low = 0, high = size;
+	while (low < high) {
+		unsigned mid = low + ((high - low) >> 1);
+		int cmp = compareenv(&env[mid], &name);
+		if (cmp < 0)
+			low = mid + 1;
+		else if (cmp > 0)
+			high = mid;
+		else
+			return mid;
 	}
-	return -1;
+	return ~low; /* not found, return 1's complement of insert position */
 }
 
 /*
@@ -763,26 +782,24 @@ static int lookupenv(char **env, const char *name, size_t nmln)
  */
 static int do_putenv(char **env, const char *name, int size, int free_old)
 {
-	char *eq = strchrnul(name, '=');
-	int i = lookupenv(env, name, eq-name);
+	int i = bsearchenv(env, name, size - 1);
 
-	if (i < 0) {
-		if (*eq) {
-			env[size - 1] = (char*) name;
-			env[size] = NULL;
+	/* optionally free removed / replaced entry */
+	if (i >= 0 && free_old)
+		free(env[i]);
+
+	if (strchr(name, '=')) {
+		/* if new value ('key=value') is specified, insert or replace entry */
+		if (i < 0) {
+			i = ~i;
+			memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
 			size++;
 		}
-	}
-	else {
-		if (free_old)
-			free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else {
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-			size--;
-		}
+		env[i] = (char*) name;
+	} else if (i >= 0) {
+		/* otherwise ('key') remove existing entry */
+		size--;
+		memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
 	}
 	return size;
 }
@@ -792,15 +809,24 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-#undef getenv
+static char *do_getenv(const char *name)
+{
+	char *value;
+	int pos = bsearchenv(environ, name, environ_size - 1);
+	if (pos < 0)
+		return NULL;
+	value = strchr(environ[pos], '=');
+	return value ? &value[1] : NULL;
+}
+
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv(name);
+	char *result = do_getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
+		result = do_getenv("TMP");
 		if (!result)
-			result = getenv("TEMP");
+			result = do_getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */
@@ -1019,9 +1045,6 @@ static wchar_t *make_environment_block(char **deltaenv)
 	for (i = 0; deltaenv && deltaenv[i]; i++)
 		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
-	/* environment must be sorted */
-	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
-
 	/* create environment block from temporary environment */
 	for (i = 0; tmpenv[i]; i++) {
 		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
@@ -2099,6 +2122,9 @@ void mingw_startup()
 	environ[i] = NULL;
 	free(buffer);
 
+	/* sort environment for O(log n) getenv / putenv */
+	qsort(environ, i, sizeof(char*), compareenv);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 78a40cbaae1d7d4edbafb46e602a9b620c44317a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:35:26 +0100
Subject: [PATCH 3424/3720] Win32: patch Windows environment on startup

Fix Windows specific environment settings on startup rather than checking
for special values on every getenv call.

As a side effect, this makes the patched environment (i.e. with properly
initialized TMPDIR and TERM) available to child processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 67c9e9c4f6..36899908ee 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -809,7 +809,7 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-static char *do_getenv(const char *name)
+char *mingw_getenv(const char *name)
 {
 	char *value;
 	int pos = bsearchenv(environ, name, environ_size - 1);
@@ -819,22 +819,6 @@ static char *do_getenv(const char *name)
 	return value ? &value[1] : NULL;
 }
 
-char *mingw_getenv(const char *name)
-{
-	char *result = do_getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = do_getenv("TMP");
-		if (!result)
-			result = do_getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 int mingw_putenv(const char *namevalue)
 {
 	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
@@ -2125,6 +2109,21 @@ void mingw_startup()
 	/* sort environment for O(log n) getenv / putenv */
 	qsort(environ, i, sizeof(char*), compareenv);
 
+	/* fix Windows specific environment settings */
+
+	/* on Windows it is TMP and TEMP */
+	if (!getenv("TMPDIR")) {
+		const char *tmp = getenv("TMP");
+		if (!tmp)
+			tmp = getenv("TEMP");
+		if (tmp)
+			setenv("TMPDIR", tmp, 1);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "winansi", 1);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 45b57ae8629eb9acc226972b95e7e3bbd8b5383f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:37:26 +0100
Subject: [PATCH 3425/3720] Win32: fix detection of empty directories in
 is_dir_empty

On Windows XP (not Win7), directories cannot be deleted while a find handle
is open, causing "Deletion of directory '...' failed. Should I try again?"
prompts.

Prior to 19d1e75d "Win32: Unicode file name support (except dirent)",
these failures were silently ignored due to strbuf_free in is_dir_empty
resetting GetLastError to ERROR_SUCCESS.

Close the find handle in is_dir_empty so that git doesn't block deletion
of the directory even after all other applications have released it.

Reported-by: John Chen 
Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 36899908ee..e6f331a581 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -243,8 +243,11 @@ static int is_dir_empty(const wchar_t *wpath)
 
 	while (!wcscmp(findbuf.cFileName, L".") ||
 			!wcscmp(findbuf.cFileName, L".."))
-		if (!FindNextFileW(handle, &findbuf))
-			return GetLastError() == ERROR_NO_MORE_FILES;
+		if (!FindNextFileW(handle, &findbuf)) {
+			DWORD err = GetLastError();
+			FindClose(handle);
+			return err == ERROR_NO_MORE_FILES;
+		}
 	FindClose(handle);
 	return 0;
 }

From 4fb5d255c866c5d6040933ea25be3c9d6adf4b19 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Fri, 23 Mar 2012 10:58:37 +0100
Subject: [PATCH 3426/3720] am: Use cat instead of echo to avoid DOS
 line-endings (fixes t4150)

Along the lines of 05d0e3b and f33946d, use cat instead of echo to avoid
line ending mismatches in the test result of "am empty-file does not
infloop" which make the test fail.

Signed-off-by: Sebastian Schuberth 
---
 git-am.sh | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/git-am.sh b/git-am.sh
index ef7191e562..a499e147b0 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -176,7 +176,9 @@ It does not apply to blobs recorded in its index.")"
 }
 
 clean_abort () {
-	test $# = 0 || echo >&2 "$@"
+	test $# = 0 || cat >&2 <
Date: Sun, 24 Jul 2011 15:54:04 +0200
Subject: [PATCH 3427/3720] t9350: point out that refs are not updated
 correctly

This happens only when the corresponding commits are not exported in
the current fast-export run. This can happen either when the relevant
commit is already marked, or when the commit is explicitly marked
as UNINTERESTING with a negative ref by another argument.

This breaks fast-export basec remote helpers.

Signed-off-by: Sverre Rabbelier 
---
 t/t9350-fast-export.sh | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 950d0ff498..74914dcc9a 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -440,4 +440,15 @@ test_expect_success 'fast-export quotes pathnames' '
 	)
 '
 
+cat > expected << EOF
+reset refs/heads/master
+from $(git rev-parse master)
+
+EOF
+
+test_expect_failure 'refs are updated even if no commits need to be exported' '
+	git fast-export master..master > actual &&
+	test_cmp expected actual
+'
+
 test_done

From 5c1c7a4867052646ccdb30e1268493512282d1a3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 15:55:26 +0200
Subject: [PATCH 3428/3720] fast-export: do not refer to non-existing marks

When calling `git fast-export a..a b` when a and b refer to the same
commit, nothing would be exported, and an incorrect reset line would
be printed for b ('from :0').

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 19509ea754..b0891b3735 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -529,9 +529,20 @@ static void get_tags_and_duplicates(struct object_array *pending,
 	}
 }
 
+static void handle_reset(const char *name, struct object *object)
+{
+	int mark = get_object_mark(object);
+
+	if (mark)
+		printf("reset %s\nfrom :%d\n\n", name,
+		       get_object_mark(object));
+	else
+		printf("reset %s\nfrom %s\n\n", name,
+		       sha1_to_hex(object->sha1));
+}
+
 static void handle_tags_and_duplicates(struct string_list *extra_refs)
 {
-	struct commit *commit;
 	int i;
 
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
@@ -543,9 +554,7 @@ static void handle_tags_and_duplicates(struct string_list *extra_refs)
 			break;
 		case OBJ_COMMIT:
 			/* create refs pointing to already seen commits */
-			commit = (struct commit *)object;
-			printf("reset %s\nfrom :%d\n\n", name,
-			       get_object_mark(&commit->object));
+			handle_reset(name, object);
 			show_progress();
 			break;
 		}

From 21e75dfc8ea8c5fe87aed7b178f81e376fb58ce3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 17:14:47 +0200
Subject: [PATCH 3429/3720] setup_revisions: remember whether a ref was
 positive or not

This will be required by fast-export, when no commits were
exported, but the refs should be set, of course.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 object.h   |  2 +-
 revision.c | 12 +++++++-----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/object.h b/object.h
index b6618d92bf..a28cd45c7c 100644
--- a/object.h
+++ b/object.h
@@ -12,7 +12,7 @@ struct object_array {
 	struct object_array_entry {
 		struct object *item;
 		const char *name;
-		unsigned mode;
+		unsigned mode, flags;
 	} *objects;
 };
 
diff --git a/revision.c b/revision.c
index b3554ed11b..3cdd0a358d 100644
--- a/revision.c
+++ b/revision.c
@@ -185,7 +185,7 @@ void mark_parents_uninteresting(struct commit *commit)
 	}
 }
 
-static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
+static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode, unsigned flags)
 {
 	if (!obj)
 		return;
@@ -206,11 +206,12 @@ static void add_pending_object_with_mode(struct rev_info *revs, struct object *o
 			return;
 	}
 	add_object_array_with_mode(obj, name, &revs->pending, mode);
+	revs->pending.objects[revs->pending.nr-1].flags = flags;
 }
 
 void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
 {
-	add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
+	add_pending_object_with_mode(revs, obj, name, S_IFINVALID, 0);
 }
 
 void add_head_to_pending(struct rev_info *revs)
@@ -1176,7 +1177,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
 					REV_CMD_LEFT, a_flags);
 			add_rev_cmdline(revs, &b->object, next,
 					REV_CMD_RIGHT, flags);
-			add_pending_object(revs, &a->object, this);
+			add_pending_object_with_mode(revs, &a->object, this,
+						     S_IFINVALID, flags_exclude);
 			add_pending_object(revs, &b->object, next);
 			return 0;
 		}
@@ -1207,7 +1209,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
 		verify_non_filename(revs->prefix, arg);
 	object = get_reference(revs, arg, sha1, flags ^ local_flags);
 	add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
-	add_pending_object_with_mode(revs, object, arg, mode);
+	add_pending_object_with_mode(revs, object, arg, mode, local_flags);
 	return 0;
 }
 
@@ -1820,7 +1822,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 		if (get_sha1_with_mode(revs->def, sha1, &mode))
 			die("bad default revision '%s'", revs->def);
 		object = get_reference(revs, revs->def, sha1, 0);
-		add_pending_object_with_mode(revs, object, revs->def, mode);
+		add_pending_object_with_mode(revs, object, revs->def, mode, 0);
 	}
 
 	/* Did the user ask for any diff output? Run the diff! */

From a5bddec59cfc5b005554106b24b1a9f5e2179465 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 15:40:23 +0200
Subject: [PATCH 3430/3720] fast-export: do not export negative refs

When calling `git fast-export master..next` we want to export
refs/heads/next, but not refs/heads/master.

Currently this is not a problem, because negative refs' commits
are never shown. In the next commit this will be changed in order
to make sure that 'master..master' does export master. I.e. even
refs whose commits are not shown are exported.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index b0891b3735..0dc5124675 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -484,7 +484,7 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		struct commit *commit = commit;
 		char *full_name;
 
-		if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
+		if ((e->flags & UNINTERESTING) || dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
 			continue;
 
 		switch (e->item->type) {

From aa1863f30541cbd572ed58b82d564ac6e69f5350 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 17:14:47 +0200
Subject: [PATCH 3431/3720] setup_revisions: remember whether a ref was
 positive or not

This will be required by fast-export, when no commits were
exported, but the refs should be set, of course.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c  | 36 +++++++++++++++++++++++++++++++-----
 t/t9350-fast-export.sh |  2 +-
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 0dc5124675..137792d49d 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -18,6 +18,8 @@
 #include "parse-options.h"
 #include "quote.h"
 
+#define REF_HANDLED (ALL_REV_FLAGS + 1)
+
 static const char *fast_export_usage[] = {
 	"git fast-export [rev-list-opts]",
 	NULL
@@ -473,6 +475,7 @@ static void handle_tag(const char *name, struct tag *tag)
 }
 
 static void get_tags_and_duplicates(struct object_array *pending,
+				    struct string_list *refs,
 				    struct string_list *extra_refs)
 {
 	struct tag *tag;
@@ -524,8 +527,11 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		if (commit->util)
 			/* more than one name for the same object */
 			string_list_append(extra_refs, full_name)->util = commit;
-		else
+		else {
 			commit->util = full_name;
+			/* we might need to set this ref explicitly */
+			string_list_append(refs, full_name)->util = commit;
+		}
 	}
 }
 
@@ -541,10 +547,29 @@ static void handle_reset(const char *name, struct object *object)
 		       sha1_to_hex(object->sha1));
 }
 
-static void handle_tags_and_duplicates(struct string_list *extra_refs)
+static void handle_tags_and_duplicates(struct string_list *refs, struct string_list *extra_refs)
 {
 	int i;
 
+	/* even if no commits were exported, we need to export the ref */
+	for (i = refs->nr - 1; i >= 0; i--) {
+		const char *name = refs->items[i].string;
+		struct object *object = refs->items[i].util;
+
+		if (!(object->flags & REF_HANDLED)) {
+			if (object->type & OBJ_TAG)
+				handle_tag(name, (struct tag *)object);
+			else {
+				if (!prefixcmp(name, "refs/tags/") &&
+				    (tag_of_filtered_mode != REWRITE ||
+				     !get_object_mark(object)))
+					continue;
+				handle_reset(name, object);
+				object->flags |= REF_HANDLED;
+			}
+		}
+	}
+
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
 		const char *name = extra_refs->items[i].string;
 		struct object *object = extra_refs->items[i].util;
@@ -634,7 +659,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info revs;
 	struct object_array commits = OBJECT_ARRAY_INIT;
-	struct string_list extra_refs = STRING_LIST_INIT_NODUP;
+	struct string_list refs = STRING_LIST_INIT_NODUP, extra_refs = STRING_LIST_INIT_NODUP;
 	struct commit *commit;
 	char *export_filename = NULL, *import_filename = NULL;
 	struct option options[] = {
@@ -684,7 +709,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 	if (import_filename && revs.prune_data.nr)
 		full_tree = 1;
 
-	get_tags_and_duplicates(&revs.pending, &extra_refs);
+	get_tags_and_duplicates(&revs.pending, &refs, &extra_refs);
 
 	if (prepare_revision_walk(&revs))
 		die("revision walk setup failed");
@@ -696,11 +721,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 		}
 		else {
 			handle_commit(commit, &revs);
+			commit->object.flags |= REF_HANDLED;
 			handle_tail(&commits, &revs);
 		}
 	}
 
-	handle_tags_and_duplicates(&extra_refs);
+	handle_tags_and_duplicates(&refs, &extra_refs);
 
 	if (export_filename)
 		export_marks(export_filename);
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 74914dcc9a..ea7dc21b9d 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -446,7 +446,7 @@ from $(git rev-parse master)
 
 EOF
 
-test_expect_failure 'refs are updated even if no commits need to be exported' '
+test_expect_success 'refs are updated even if no commits need to be exported' '
 	git fast-export master..master > actual &&
 	test_cmp expected actual
 '

From 05c850e702f197a63e5aae2a5249f46cd7377445 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Fri, 15 Jul 2011 16:37:28 +0200
Subject: [PATCH 3432/3720] t5800: test pushing a new branch with old content

This works now that fast-export has been fixed to properly handle
refs that point to a commit that was not exported during the current
fast-export run.
---
 t/t5800-remote-helpers.sh | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 1c62001fce..68f8418f62 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -125,6 +125,14 @@ test_expect_success 'push new branch by name' '
 	compare_refs clone HEAD server refs/heads/new-name
 '
 
+test_expect_failure 'push new branch with old content' '
+	(cd clone &&
+	 git checkout -b existing &&
+	 git push origin existing
+	) &&
+	compare_refs clone refs/heads/existing server refs/heads/existing
+'
+
 test_expect_failure 'push new branch with old:new refspec' '
 	(cd clone &&
 	 git push origin new-name:new-refspec

From 62f33cc14e64014c529494a7f218d46dd68595e8 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Fri, 15 Jul 2011 21:55:01 +0200
Subject: [PATCH 3433/3720] t5800: point out that deleting branches does not
 work

This test actually breaks the repositories involved somehow, so it is
not enabled by default.
---
 t/t5800-remote-helpers.sh | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 68f8418f62..0be4c7ef79 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -125,7 +125,7 @@ test_expect_success 'push new branch by name' '
 	compare_refs clone HEAD server refs/heads/new-name
 '
 
-test_expect_failure 'push new branch with old content' '
+test_expect_success 'push new branch with old content' '
 	(cd clone &&
 	 git checkout -b existing &&
 	 git push origin existing
@@ -133,6 +133,17 @@ test_expect_failure 'push new branch with old content' '
 	compare_refs clone refs/heads/existing server refs/heads/existing
 '
 
+test_expect_failure BROKEN 'delete branch' '
+	(cd clone &&
+	 git checkout -b delete-me &&
+	 echo content >>file &&
+	 git commit -a -m eight &&
+	 git push origin delete-me
+	 git push origin :delete-me) &&
+	test_must_fail git --git-dir="server/.git" rev-parse --verify delete-me
+'
+
+
 test_expect_failure 'push new branch with old:new refspec' '
 	(cd clone &&
 	 git push origin new-name:new-refspec

From ce0854042befce803a4c3f4959d2a3efdf151f28 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sat, 28 Aug 2010 20:49:01 -0500
Subject: [PATCH 3434/3720] transport-helper: add trailing --

---
 transport-helper.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/transport-helper.c b/transport-helper.c
index f6b3b1fb79..4bdccc665a 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -398,7 +398,7 @@ static int get_exporter(struct transport *transport,
 	/* we need to duplicate helper->in because we want to use it after
 	 * fastexport is done with it. */
 	fastexport->out = dup(helper->in);
-	fastexport->argv = xcalloc(5 + revlist_args->nr, sizeof(*fastexport->argv));
+	fastexport->argv = xcalloc(6 + revlist_args->nr, sizeof(*fastexport->argv));
 	fastexport->argv[argc++] = "fast-export";
 	fastexport->argv[argc++] = "--use-done-feature";
 	if (data->export_marks)
@@ -409,6 +409,8 @@ static int get_exporter(struct transport *transport,
 	for (i = 0; i < revlist_args->nr; i++)
 		fastexport->argv[argc++] = revlist_args->items[i].string;
 
+	fastexport->argv[argc++] = "--";
+
 	fastexport->git_cmd = 1;
 	return start_command(fastexport);
 }

From 91bff21ed023116afdf6cefd6d1dbab9e4faaf77 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 00:06:00 +0200
Subject: [PATCH 3435/3720] remote-helper: check helper status after
 import/export

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/clone.c    |  4 +++-
 transport-helper.c | 16 ++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index bbd5c96237..8e76a747aa 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -821,7 +821,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 			}
 
 		if (!is_local && !complete_refs_before_fetch)
-			transport_fetch_refs(transport, mapped_refs);
+			if (transport_fetch_refs(transport, mapped_refs))
+				die(_("could not fetch refs from %s"),
+				    transport->url);
 
 		remote_head = find_ref_by_name(refs, "HEAD");
 		remote_head_points_at =
diff --git a/transport-helper.c b/transport-helper.c
index 4bdccc665a..f157b627d0 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -415,6 +415,19 @@ static int get_exporter(struct transport *transport,
 	return start_command(fastexport);
 }
 
+static void check_helper_status(struct helper_data *data)
+{
+	int pid, status;
+
+	pid = waitpid(data->helper->pid, &status, WNOHANG);
+	if (pid < 0)
+		die("Could not retrieve status of remote helper '%s'",
+		    data->name);
+	if (pid > 0 && WIFEXITED(status))
+		die("Remote helper '%s' died with %d",
+		    data->name, WEXITSTATUS(status));
+}
+
 static int fetch_with_import(struct transport *transport,
 			     int nr_heads, struct ref **to_fetch)
 {
@@ -443,6 +456,8 @@ static int fetch_with_import(struct transport *transport,
 
 	if (finish_command(&fastimport))
 		die("Error while running fast-import");
+	check_helper_status(data);
+
 	free(fastimport.argv);
 	fastimport.argv = NULL;
 
@@ -771,6 +786,7 @@ static int push_refs_with_export(struct transport *transport,
 
 	if (finish_command(&exporter))
 		die("Error while running fast-export");
+	check_helper_status(data);
 	push_update_refs_status(data, remote_refs);
 	return 0;
 }

From 701ba60ebfa5e2c2cd81355ecc6ac66c94324e5b Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 00:11:18 +0200
Subject: [PATCH 3436/3720] remote-testgit: factor out RemoteHelper class

Facilitate writing import-export based helpers in python by
refactoring common code to a base class.

Signed-off-by: Sverre Rabbelier 
---
 git-remote-testgit.py              | 288 ++++++-----------------------
 git_remote_helpers/git/importer.py |  28 +--
 git_remote_helpers/helper.py       | 200 ++++++++++++++++++++
 3 files changed, 260 insertions(+), 256 deletions(-)
 create mode 100644 git_remote_helpers/helper.py

diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index 3dc4851cfc..d57c1dc393 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -1,265 +1,95 @@
 #!/usr/bin/env python
 
-# This command is a simple remote-helper, that is used both as a
-# testcase for the remote-helper functionality, and as an example to
-# show remote-helper authors one possible implementation.
-#
-# This is a Git <-> Git importer/exporter, that simply uses git
-# fast-import and git fast-export to consume and produce fast-import
-# streams.
-#
-# To understand better the way things work, one can activate debug
-# traces by setting (to any value) the environment variables
-# GIT_TRANSPORT_HELPER_DEBUG and GIT_DEBUG_TESTGIT, to see messages
-# from the transport-helper side, or from this example remote-helper.
-
-# hashlib is only available in python >= 2.5
-try:
-    import hashlib
-    _digest = hashlib.sha1
-except ImportError:
-    import sha
-    _digest = sha.new
 import sys
 import os
 sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
 
-from git_remote_helpers.util import die, debug, warn
+from git_remote_helpers.helper import RemoteHelper
+from git_remote_helpers.util import check_output, debug
 from git_remote_helpers.git.repo import GitRepo
 from git_remote_helpers.git.exporter import GitExporter
 from git_remote_helpers.git.importer import GitImporter
 from git_remote_helpers.git.non_local import NonLocalGit
 
-def get_repo(alias, url):
-    """Returns a git repository object initialized for usage.
-    """
 
-    repo = GitRepo(url)
-    repo.get_revs()
-    repo.get_head()
+class TestgitRemoteHelper(RemoteHelper):
+    def get_repo(self, alias, url):
+        """Returns a git repository object initialized for usage.
+        """
 
-    hasher = _digest()
-    hasher.update(repo.path)
-    repo.hash = hasher.hexdigest()
+        repo = GitRepo(url)
+        repo.get_revs()
+        repo.get_head()
 
-    repo.get_base_path = lambda base: os.path.join(
-        base, 'info', 'fast-import', repo.hash)
+        prefix = 'refs/testgit/%s/' % alias
+        debug("prefix: '%s'", prefix)
 
-    prefix = 'refs/testgit/%s/' % alias
-    debug("prefix: '%s'", prefix)
+        repo.marksfile = 'testgit.marks'
+        repo.prefix = prefix
 
-    repo.gitdir = os.environ["GIT_DIR"]
-    repo.alias = alias
-    repo.prefix = prefix
+        self.setup_repo(repo, alias)
 
-    repo.exporter = GitExporter(repo)
-    repo.importer = GitImporter(repo)
-    repo.non_local = NonLocalGit(repo)
+        repo.exporter = GitExporter(repo)
+        repo.importer = GitImporter(repo)
+        repo.non_local = NonLocalGit(repo)
 
-    return repo
-
-
-def local_repo(repo, path):
-    """Returns a git repository object initalized for usage.
-    """
-
-    local = GitRepo(path)
-
-    local.non_local = None
-    local.gitdir = repo.gitdir
-    local.alias = repo.alias
-    local.prefix = repo.prefix
-    local.hash = repo.hash
-    local.get_base_path = repo.get_base_path
-    local.exporter = GitExporter(local)
-    local.importer = GitImporter(local)
-
-    return local
-
-
-def do_capabilities(repo, args):
-    """Prints the supported capabilities.
-    """
-
-    print "import"
-    print "export"
-    print "refspec refs/heads/*:%s*" % repo.prefix
-
-    dirname = repo.get_base_path(repo.gitdir)
-
-    if not os.path.exists(dirname):
-        os.makedirs(dirname)
-
-    path = os.path.join(dirname, 'testgit.marks')
-
-    print "*export-marks %s" % path
-    if os.path.exists(path):
-        print "*import-marks %s" % path
-
-    print # end capabilities
-
-
-def do_list(repo, args):
-    """Lists all known references.
-
-    Bug: This will always set the remote head to master for non-local
-    repositories, since we have no way of determining what the remote
-    head is at clone time.
-    """
-
-    for ref in repo.revs:
-        debug("? refs/heads/%s", ref)
-        print "? refs/heads/%s" % ref
-
-    if repo.head:
-        debug("@refs/heads/%s HEAD" % repo.head)
-        print "@refs/heads/%s HEAD" % repo.head
-    else:
-        debug("@refs/heads/master HEAD")
-        print "@refs/heads/master HEAD"
-
-    print # end list
-
-
-def update_local_repo(repo):
-    """Updates (or clones) a local repo.
-    """
-
-    if repo.local:
         return repo
 
-    path = repo.non_local.clone(repo.gitdir)
-    repo.non_local.update(repo.gitdir)
-    repo = local_repo(repo, path)
-    return repo
+    def local_repo(self, repo, path):
+        """Returns a git repository object initalized for usage.
+        """
 
+        local = GitRepo(path)
 
-def do_import(repo, args):
-    """Exports a fast-import stream from testgit for git to import.
-    """
+        self.setup_local_repo(local, repo)
 
-    if len(args) != 1:
-        die("Import needs exactly one ref")
+        local.exporter = GitExporter(local)
+        local.importer = GitImporter(local)
 
-    if not repo.gitdir:
-        die("Need gitdir to import")
+        return local
 
-    ref = args[0]
-    refs = [ref]
+    def do_list(self, repo, args):
+        """Lists all known references.
 
-    while True:
-        line = sys.stdin.readline()
-        if line == '\n':
-            break
-        if not line.startswith('import '):
-            die("Expected import line.")
+        Bug: This will always set the remote head to master for non-local
+        repositories, since we have no way of determining what the remote
+        head is at clone time.
+        """
 
-        # strip of leading 'import '
-        ref = line[7:].strip()
-        refs.append(ref)
+        for ref in repo.revs:
+            debug("? refs/heads/%s", ref)
+            print "? refs/heads/%s" % ref
 
-    repo = update_local_repo(repo)
-    repo.exporter.export_repo(repo.gitdir, refs)
+        if repo.head:
+            debug("@refs/heads/%s HEAD" % repo.head)
+            print "@refs/heads/%s HEAD" % repo.head
+        else:
+            debug("@refs/heads/master HEAD")
+            print "@refs/heads/master HEAD"
 
-    print "done"
+        print # end list
 
+    def sanitize(self, value):
+        """Cleans up the url.
+        """
 
-def do_export(repo, args):
-    """Imports a fast-import stream from git to testgit.
-    """
+        if value.startswith('testgit::'):
+            value = value[9:]
 
-    if not repo.gitdir:
-        die("Need gitdir to export")
+        return value
 
-    update_local_repo(repo)
-    changed = repo.importer.do_import(repo.gitdir)
+    def get_refs(self, repo, gitdir):
+        """Returns a dictionary with refs.
+        """
+        args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
+        lines = check_output(args).strip().split('\n')
+        refs = {}
+        for line in lines:
+            value, name = line.split(' ')
+            name = name.strip('commit\t')
+            refs[name] = value
+        return refs
 
-    if not repo.local:
-        repo.non_local.push(repo.gitdir)
-
-    for ref in changed:
-        print "ok %s" % ref
-    print
-
-
-COMMANDS = {
-    'capabilities': do_capabilities,
-    'list': do_list,
-    'import': do_import,
-    'export': do_export,
-}
-
-
-def sanitize(value):
-    """Cleans up the url.
-    """
-
-    if value.startswith('testgit::'):
-        value = value[9:]
-
-    return value
-
-
-def read_one_line(repo):
-    """Reads and processes one command.
-    """
-
-    line = sys.stdin.readline()
-
-    cmdline = line
-
-    if not cmdline:
-        warn("Unexpected EOF")
-        return False
-
-    cmdline = cmdline.strip().split()
-    if not cmdline:
-        # Blank line means we're about to quit
-        return False
-
-    cmd = cmdline.pop(0)
-    debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
-
-    if cmd not in COMMANDS:
-        die("Unknown command, %s", cmd)
-
-    func = COMMANDS[cmd]
-    func(repo, cmdline)
-    sys.stdout.flush()
-
-    return True
-
-
-def main(args):
-    """Starts a new remote helper for the specified repository.
-    """
-
-    if len(args) != 3:
-        die("Expecting exactly three arguments.")
-        sys.exit(1)
-
-    if os.getenv("GIT_DEBUG_TESTGIT"):
-        import git_remote_helpers.util
-        git_remote_helpers.util.DEBUG = True
-
-    alias = sanitize(args[1])
-    url = sanitize(args[2])
-
-    if not alias.isalnum():
-        warn("non-alnum alias '%s'", alias)
-        alias = "tmp"
-
-    args[1] = alias
-    args[2] = url
-
-    repo = get_repo(alias, url)
-
-    debug("Got arguments %s", args[1:])
-
-    more = True
-
-    while (more):
-        more = read_one_line(repo)
 
 if __name__ == '__main__':
-    sys.exit(main(sys.argv))
+    sys.exit(TestgitRemoteHelper().main(sys.argv))
diff --git a/git_remote_helpers/git/importer.py b/git_remote_helpers/git/importer.py
index 5c6b595e16..02a719ac02 100644
--- a/git_remote_helpers/git/importer.py
+++ b/git_remote_helpers/git/importer.py
@@ -1,7 +1,7 @@
 import os
 import subprocess
 
-from git_remote_helpers.util import check_call, check_output
+from git_remote_helpers.util import check_call
 
 
 class GitImporter(object):
@@ -16,18 +16,6 @@ class GitImporter(object):
 
         self.repo = repo
 
-    def get_refs(self, gitdir):
-        """Returns a dictionary with refs.
-        """
-        args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
-        lines = check_output(args).strip().split('\n')
-        refs = {}
-        for line in lines:
-            value, name = line.split(' ')
-            name = name.strip('commit\t')
-            refs[name] = value
-        return refs
-
     def do_import(self, base):
         """Imports a fast-import stream to the given directory.
 
@@ -44,23 +32,9 @@ class GitImporter(object):
         if not os.path.exists(dirname):
             os.makedirs(dirname)
 
-        refs_before = self.get_refs(gitdir)
-
         args = ["git", "--git-dir=" + gitdir, "fast-import", "--quiet", "--export-marks=" + path]
 
         if os.path.exists(path):
             args.append("--import-marks=" + path)
 
         check_call(args)
-
-        refs_after = self.get_refs(gitdir)
-
-        changed = {}
-
-        for name, value in refs_after.iteritems():
-            if refs_before.get(name) == value:
-                continue
-
-            changed[name] = value
-
-        return changed
diff --git a/git_remote_helpers/helper.py b/git_remote_helpers/helper.py
new file mode 100644
index 0000000000..a2e968e8d8
--- /dev/null
+++ b/git_remote_helpers/helper.py
@@ -0,0 +1,200 @@
+import os
+import sys
+
+# hashlib is only available in python >= 2.5
+try:
+    import hashlib
+    _digest = hashlib.sha1
+except ImportError:
+    import sha
+    _digest = sha.new
+
+from git_remote_helpers.util import debug, die, warn
+
+
+class RemoteHelper(object):
+    def __init__(self):
+        self.commands = {
+            'capabilities': self.do_capabilities,
+            'list': self.do_list,
+            'import': self.do_import,
+            'export': self.do_export,
+        }
+
+    def setup_repo(self, repo, alias):
+        """Returns a git repository object initialized for usage.
+        """
+
+        hasher = _digest()
+        hasher.update(repo.path)
+        repo.hash = hasher.hexdigest()
+
+        repo.get_base_path = lambda base: os.path.join(
+            base, 'info', 'fast-import', repo.hash)
+
+        repo.gitdir = os.environ["GIT_DIR"]
+        repo.alias = alias
+
+    def setup_local_repo(self, local, repo):
+        """Returns a git repository object initalized for usage.
+        """
+        local.non_local = None
+        local.gitdir = repo.gitdir
+        local.alias = repo.alias
+        local.prefix = repo.prefix
+        local.hash = repo.hash
+        local.get_base_path = repo.get_base_path
+
+    def do_capabilities(self, repo, args):
+        """Prints the supported capabilities.
+        """
+
+        print "import"
+        print "export"
+        print "refspec refs/heads/*:%s*" % repo.prefix
+
+        dirname = repo.get_base_path(repo.gitdir)
+
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+
+        path = os.path.join(dirname, repo.marksfile)
+
+        print "*export-marks %s" % path
+        if os.path.exists(path):
+            print "*import-marks %s" % path
+
+        print # end capabilities
+
+    def update_local_repo(self, repo):
+        """Updates (or clones) a local repo.
+        """
+
+        if repo.local:
+            return repo
+
+        path = repo.non_local.clone(repo.gitdir)
+        repo.non_local.update(repo.gitdir)
+        repo = self.local_repo(repo, path)
+        return repo
+
+    def do_import(self, repo, args):
+        """Exports a fast-import stream from testgit for git to import.
+        """
+
+        if len(args) != 1:
+            die("Import needs exactly one ref")
+
+        if not repo.gitdir:
+            die("Need gitdir to import")
+
+        ref = args[0]
+        refs = [ref]
+
+        while True:
+            line = sys.stdin.readline()
+            if line == '\n':
+                break
+            if not line.startswith('import '):
+                die("Expected import line.")
+
+            # strip of leading 'import '
+            ref = line[7:].strip()
+            refs.append(ref)
+
+        repo = self.update_local_repo(repo)
+
+        repo.exporter.export_repo(repo.gitdir, refs)
+
+        print "done"
+
+    def do_export(self, repo, args):
+        """Imports a fast-import stream from git to testgit.
+        """
+
+        if not repo.gitdir:
+            die("Need gitdir to export")
+
+        localrepo = self.update_local_repo(repo)
+
+        refs_before = self.get_refs(repo, repo.gitdir)
+        localrepo.importer.do_import(localrepo.gitdir)
+        refs_after = self.get_refs(repo, repo.gitdir)
+
+        changed = {}
+
+        for name, value in refs_after.iteritems():
+            if refs_before.get(name) == value:
+                continue
+
+            changed[name] = value
+
+        if not repo.local:
+            repo.non_local.push(repo.gitdir)
+
+        for ref in changed:
+            print "ok %s" % ref
+        print
+
+    def read_one_line(self, repo):
+        """Reads and processes one command.
+        """
+
+        line = sys.stdin.readline()
+
+        cmdline = line
+
+        if not cmdline:
+            warn("Unexpected EOF")
+            return False
+
+        cmdline = cmdline.strip().split()
+        if not cmdline:
+            # Blank line means we're about to quit
+            return False
+
+        cmd = cmdline.pop(0)
+        debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
+
+        if cmd not in self.commands:
+            die("Unknown command, %s", cmd)
+
+        func = self.commands[cmd]
+        func(repo, cmdline)
+        sys.stdout.flush()
+
+        return True
+
+    def main(self, args):
+        """Starts a new remote helper for the specified repository.
+        """
+
+        if len(args) != 3:
+            die("Expecting exactly three arguments.")
+            sys.exit(1)
+
+        if os.getenv("GIT_REMOTE_HELPER_DEBUG"):
+            import git_remote_helpers.util
+            git_remote_helpers.util.DEBUG = True
+
+        alias = self.sanitize(args[1])
+        url = self.sanitize(args[2])
+
+        if not alias.isalnum():
+            warn("non-alnum alias '%s'", alias)
+            alias = "tmp"
+
+        args[1] = alias
+        args[2] = url
+
+        repo = self.get_repo(alias, url)
+
+        debug("Got arguments %s", args[1:])
+
+        more = True
+
+        while (more):
+            more = self.read_one_line(repo)
+
+    if __name__ == '__main__':
+        sys.exit(main(sys.argv))

From 70c5519b8f83c5b95e6a76814eb4070d4057bdf8 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 13:43:34 +0200
Subject: [PATCH 3437/3720] git-remote-testgit: make local a function

Other helpers (such as git-remote-hg) require that 'self.local' is a
function, rather than a variable.
---
 git_remote_helpers/git/importer.py | 2 +-
 git_remote_helpers/git/repo.py     | 6 +++---
 git_remote_helpers/helper.py       | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/git_remote_helpers/git/importer.py b/git_remote_helpers/git/importer.py
index 02a719ac02..b7d6107933 100644
--- a/git_remote_helpers/git/importer.py
+++ b/git_remote_helpers/git/importer.py
@@ -23,7 +23,7 @@ class GitImporter(object):
         """
 
         dirname = self.repo.get_base_path(base)
-        if self.repo.local:
+        if self.repo.local():
             gitdir = self.repo.gitpath
         else:
             gitdir = os.path.abspath(os.path.join(dirname, '.git'))
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
index acbf8d7785..4536233868 100644
--- a/git_remote_helpers/git/repo.py
+++ b/git_remote_helpers/git/repo.py
@@ -38,14 +38,14 @@ class GitRepo(object):
         self.path = path
         self.head = None
         self.revmap = {}
-        self.local = not is_remote(self.path)
+        self.local = lambda: not is_remote(self.path)
 
         if(self.path.endswith('.git')):
             self.gitpath = self.path
         else:
             self.gitpath = os.path.join(self.path, '.git')
 
-        if self.local and not os.path.exists(self.gitpath):
+        if self.local() and not os.path.exists(self.gitpath):
             os.makedirs(self.gitpath)
 
     def get_revs(self):
@@ -68,7 +68,7 @@ class GitRepo(object):
         """Determines the head of a local repo.
         """
 
-        if not self.local:
+        if not self.local():
             return
 
         path = os.path.join(self.gitpath, "HEAD")
diff --git a/git_remote_helpers/helper.py b/git_remote_helpers/helper.py
index a2e968e8d8..164c8b578f 100644
--- a/git_remote_helpers/helper.py
+++ b/git_remote_helpers/helper.py
@@ -70,7 +70,7 @@ class RemoteHelper(object):
         """Updates (or clones) a local repo.
         """
 
-        if repo.local:
+        if repo.local():
             return repo
 
         path = repo.non_local.clone(repo.gitdir)
@@ -129,7 +129,7 @@ class RemoteHelper(object):
 
             changed[name] = value
 
-        if not repo.local:
+        if not repo.local():
             repo.non_local.push(repo.gitdir)
 
         for ref in changed:

From 654506ab380ec8c666cfc729f2c2fe0a2e74e486 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 22 Aug 2010 01:22:14 -0500
Subject: [PATCH 3438/3720] git_remote_helpers: add fastimport library

---
 git_remote_helpers/fastimport/__init__.py     |   0
 git_remote_helpers/fastimport/commands.py     | 469 +++++++++++++
 git_remote_helpers/fastimport/dates.py        |  79 +++
 git_remote_helpers/fastimport/errors.py       | 182 +++++
 git_remote_helpers/fastimport/head_tracker.py |  47 ++
 git_remote_helpers/fastimport/helpers.py      |  88 +++
 git_remote_helpers/fastimport/idmapfile.py    |  65 ++
 git_remote_helpers/fastimport/parser.py       | 621 ++++++++++++++++++
 git_remote_helpers/fastimport/processor.py    | 222 +++++++
 git_remote_helpers/setup.py                   |   3 +-
 10 files changed, 1775 insertions(+), 1 deletion(-)
 create mode 100644 git_remote_helpers/fastimport/__init__.py
 create mode 100644 git_remote_helpers/fastimport/commands.py
 create mode 100644 git_remote_helpers/fastimport/dates.py
 create mode 100644 git_remote_helpers/fastimport/errors.py
 create mode 100644 git_remote_helpers/fastimport/head_tracker.py
 create mode 100644 git_remote_helpers/fastimport/helpers.py
 create mode 100644 git_remote_helpers/fastimport/idmapfile.py
 create mode 100644 git_remote_helpers/fastimport/parser.py
 create mode 100644 git_remote_helpers/fastimport/processor.py

diff --git a/git_remote_helpers/fastimport/__init__.py b/git_remote_helpers/fastimport/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/git_remote_helpers/fastimport/commands.py b/git_remote_helpers/fastimport/commands.py
new file mode 100644
index 0000000000..b3c86c4910
--- /dev/null
+++ b/git_remote_helpers/fastimport/commands.py
@@ -0,0 +1,469 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Import command classes."""
+
+import os
+
+# There is a bug in git 1.5.4.3 and older by which unquoting a string consumes
+# one extra character. Set this variable to True to work-around it. It only
+# happens when renaming a file whose name contains spaces and/or quotes, and
+# the symptom is:
+#   % git-fast-import
+#   fatal: Missing space after source: R "file 1.txt" file 2.txt
+# http://git.kernel.org/?p=git/git.git;a=commit;h=c8744d6a8b27115503565041566d97c21e722584
+GIT_FAST_IMPORT_NEEDS_EXTRA_SPACE_AFTER_QUOTE = False
+
+
+# Lists of command names
+COMMAND_NAMES = ['blob', 'checkpoint', 'commit', 'feature', 'progress',
+    'reset', 'tag']
+FILE_COMMAND_NAMES = ['filemodify', 'filedelete', 'filecopy', 'filerename',
+    'filedeleteall']
+
+
+# Feature names
+MULTIPLE_AUTHORS_FEATURE = "multiple-authors"
+COMMIT_PROPERTIES_FEATURE = "commit-properties"
+EMPTY_DIRS_FEATURE = "empty-directories"
+FEATURE_NAMES = [
+    MULTIPLE_AUTHORS_FEATURE,
+    COMMIT_PROPERTIES_FEATURE,
+    EMPTY_DIRS_FEATURE,
+    ]
+
+
+# for classes with no meaningful __str__()
+def _simplerepr(self):
+    return "<%s at 0x%x>" % (self.__class__.__name__, id(self))
+
+# classes that define __str__() should use this instead
+def _detailrepr(self):
+    return ("<%s at 0x%x: %s>"
+            % (self.__class__.__name__, id(self), str(self)))
+
+
+class ImportCommand(object):
+    """Base class for import commands."""
+
+    def __init__(self, name):
+        self.name = name
+        # List of field names not to display
+        self._binary = []
+
+    __repr__ = _simplerepr
+
+    def format(self):
+        """Format this command as a fastimport dump fragment.
+
+        Returns a (possibly multiline) string that, if seen in a
+        fastimport stream, would parse to an equivalent command object.
+        """
+        raise NotImplementedError("abstract method")
+
+    def dump_str(self, names=None, child_lists=None, verbose=False):
+        """Dump fields as a string.
+
+        :param names: the list of fields to include or
+            None for all public fields
+        :param child_lists: dictionary of child command names to
+            fields for that child command to include
+        :param verbose: if True, prefix each line with the command class and
+            display fields as a dictionary; if False, dump just the field
+            values with tabs between them
+        """
+        interesting = {}
+        if names is None:
+            fields = [k for k in self.__dict__.keys() if not k.startswith('_')]
+        else:
+            fields = names
+        for field in fields:
+            value = self.__dict__.get(field)
+            if field in self._binary and value is not None:
+                value = '(...)'
+            interesting[field] = value
+        if verbose:
+            return "%s: %s" % (self.__class__.__name__, interesting)
+        else:
+            return "\t".join([repr(interesting[k]) for k in fields])
+
+
+class _MarkMixin(object):
+    """mixin for fastimport commands with a mark: blob, commit."""
+    def __init__(self, mark, location):
+        self.mark= mark
+        self.location = location
+
+        # Provide a unique id in case the mark is missing
+        if mark is None:
+            self.id = '%s@%d' % (os.path.basename(location[0]), location[1])
+        else:
+            self.id = ':%s' % mark
+
+    def __str__(self):
+        return self.id
+
+    __repr__ = _detailrepr
+
+
+class BlobCommand(ImportCommand, _MarkMixin):
+
+    def __init__(self, mark, data, location):
+        ImportCommand.__init__(self, 'blob')
+        _MarkMixin.__init__(self, mark, location)
+        self.data = data
+        self._binary = ['data']
+
+    def format(self):
+        if self.mark is None:
+            mark_line = ""
+        else:
+            mark_line = "\nmark :%s" % self.mark
+        return "blob%s\ndata %d\n%s" % (mark_line, len(self.data), self.data)
+
+
+class CheckpointCommand(ImportCommand):
+
+    def __init__(self):
+        ImportCommand.__init__(self, 'checkpoint')
+
+    def format(self):
+        return "checkpoint"
+
+
+class CommitCommand(ImportCommand, _MarkMixin):
+
+    def __init__(self, ref, mark, author, committer, message, from_,
+        merges, file_cmds, location=None, more_authors=None, properties=None):
+        ImportCommand.__init__(self, 'commit')
+        _MarkMixin.__init__(self, mark, location)
+        self.ref = ref
+        self.author = author
+        self.committer = committer
+        self.message = message
+        self.from_ = from_
+        self.merges = merges
+        self.file_cmds = file_cmds
+        self.more_authors = more_authors
+        self.properties = properties
+        self._binary = ['file_cmds']
+
+    def format(self, use_features=True, include_file_contents=True):
+        if self.mark is None:
+            mark_line = ""
+        else:
+            mark_line = "\nmark :%s" % self.mark
+        if self.author is None:
+            author_section = ""
+        else:
+            author_section = "\nauthor %s" % format_who_when(self.author)
+            if use_features and self.more_authors:
+                for author in self.more_authors:
+                    author_section += "\nauthor %s" % format_who_when(author)
+        committer = "committer %s" % format_who_when(self.committer)
+        if self.message is None:
+            msg_section = ""
+        else:
+            msg = self.message.encode('utf8')
+            msg_section = "\ndata %d\n%s" % (len(msg), msg)
+        if self.from_ is None:
+            from_line = ""
+        else:
+            from_line = "\nfrom %s" % self.from_
+        if self.merges is None:
+            merge_lines = ""
+        else:
+            merge_lines = "".join(["\nmerge %s" % (m,)
+                for m in self.merges])
+        if use_features and self.properties:
+            property_lines = []
+            for name in sorted(self.properties):
+                value = self.properties[name]
+                property_lines.append("\n" + format_property(name, value))
+            properties_section = "".join(property_lines)
+        else:
+            properties_section = ""
+        if self.file_cmds is None:
+            filecommands = ""
+        else:
+            if include_file_contents:
+                format_str = "\n%r"
+            else:
+                format_str = "\n%s"
+            filecommands = "".join(
+                ["\n" + fc.format() for fc in self.file_cmds])
+        return "commit %s%s%s\n%s%s%s%s%s%s" % (self.ref, mark_line,
+            author_section, committer, msg_section, from_line, merge_lines,
+            properties_section, filecommands)
+
+    def dump_str(self, names=None, child_lists=None, verbose=False):
+        result = [ImportCommand.dump_str(self, names, verbose=verbose)]
+        for f in self.file_cmds:
+            if child_lists is None:
+                continue
+            try:
+                child_names = child_lists[f.name]
+            except KeyError:
+                continue
+            result.append("\t%s" % f.dump_str(child_names, verbose=verbose))
+        return '\n'.join(result)
+
+
+class FeatureCommand(ImportCommand):
+
+    def __init__(self, feature_name, value=None, location=None):
+        ImportCommand.__init__(self, 'feature')
+        self.feature_name = feature_name
+        self.value = value
+        self.location = location
+
+    def format(self):
+        if self.value is None:
+            value_text = ""
+        else:
+            value_text = "=%s" % self.value
+        return "feature %s%s" % (self.feature_name, value_text)
+
+
+class ProgressCommand(ImportCommand):
+
+    def __init__(self, message):
+        ImportCommand.__init__(self, 'progress')
+        self.message = message
+
+    def format(self):
+        return "progress %s" % (self.message,)
+
+
+class ResetCommand(ImportCommand):
+
+    def __init__(self, ref, from_):
+        ImportCommand.__init__(self, 'reset')
+        self.ref = ref
+        self.from_ = from_
+
+    def format(self):
+        if self.from_ is None:
+            from_line = ""
+        else:
+            # According to git-fast-import(1), the extra LF is optional here;
+            # however, versions of git up to 1.5.4.3 had a bug by which the LF
+            # was needed. Always emit it, since it doesn't hurt and maintains
+            # compatibility with older versions.
+            # http://git.kernel.org/?p=git/git.git;a=commit;h=655e8515f279c01f525745d443f509f97cd805ab
+            from_line = "\nfrom %s\n" % self.from_
+        return "reset %s%s" % (self.ref, from_line)
+
+
+class TagCommand(ImportCommand):
+
+    def __init__(self, id, from_, tagger, message):
+        ImportCommand.__init__(self, 'tag')
+        self.id = id
+        self.from_ = from_
+        self.tagger = tagger
+        self.message = message
+
+    def __str__(self):
+        return self.id
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        if self.from_ is None:
+            from_line = ""
+        else:
+            from_line = "\nfrom %s" % self.from_
+        if self.tagger is None:
+            tagger_line = ""
+        else:
+            tagger_line = "\ntagger %s" % format_who_when(self.tagger)
+        if self.message is None:
+            msg_section = ""
+        else:
+            msg = self.message.encode('utf8')
+            msg_section = "\ndata %d\n%s" % (len(msg), msg)
+        return "tag %s%s%s%s" % (self.id, from_line, tagger_line, msg_section)
+
+
+class FileCommand(ImportCommand):
+    """Base class for file commands."""
+    pass
+
+
+class FileModifyCommand(FileCommand):
+
+    def __init__(self, path, mode, dataref, data):
+        # Either dataref or data should be null
+        FileCommand.__init__(self, 'filemodify')
+        self.path = check_path(path)
+        self.mode = mode
+        self.dataref = dataref
+        self.data = data
+        self._binary = ['data']
+
+    def __str__(self):
+        return self.path
+
+    __repr__ = _detailrepr
+
+    def format(self, include_file_contents=True):
+        datastr = ""
+        if self.dataref is None:
+            dataref = "inline"
+            if include_file_contents:
+                datastr = "\ndata %d\n%s" % (len(self.data), self.data)
+        else:
+            dataref = "%s" % (self.dataref,)
+        path = format_path(self.path)
+        return "M %s %s %s%s" % (self.mode, dataref, path, datastr)
+
+    def is_regular(self):
+        """Return true if this is a regular file (mode 644)."""
+        return self.mode.endswith("644")
+
+    def is_executable(self):
+        """Return true if this is an executable file (mode 755)."""
+        return self.mode.endswith("755")
+
+    def is_symlink(self):
+        """Return true if this is a symlink (mode 120000)."""
+        return self.mode == "120000"
+
+    def is_gitlink(self):
+        """Return true if this is a gitlink (mode 160000)."""
+        return self.mode == "160000"
+
+
+class FileDeleteCommand(FileCommand):
+
+    def __init__(self, path):
+        FileCommand.__init__(self, 'filedelete')
+        self.path = check_path(path)
+
+    def __str__(self):
+        return self.path
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "D %s" % (format_path(self.path),)
+
+
+class FileCopyCommand(FileCommand):
+
+    def __init__(self, src_path, dest_path):
+        FileCommand.__init__(self, 'filecopy')
+        self.src_path = check_path(src_path)
+        self.dest_path = check_path(dest_path)
+
+    def __str__(self):
+        return "%s -> %s" % (self.src_path, self.dest_path)
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "C %s %s" % (
+            format_path(self.src_path, quote_spaces=True),
+            format_path(self.dest_path))
+
+
+class FileRenameCommand(FileCommand):
+
+    def __init__(self, old_path, new_path):
+        FileCommand.__init__(self, 'filerename')
+        self.old_path = check_path(old_path)
+        self.new_path = check_path(new_path)
+
+    def __str__(self):
+        return "%s -> %s" % (self.old_path, self.new_path)
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "R %s %s" % (
+            format_path(self.old_path, quote_spaces=True),
+            format_path(self.new_path))
+
+
+class FileDeleteAllCommand(FileCommand):
+
+    def __init__(self):
+        FileCommand.__init__(self, 'filedeleteall')
+
+    def format(self):
+        return "deleteall"
+
+
+def check_path(path):
+    """Check that a path is legal.
+
+    :return: the path if all is OK
+    :raise ValueError: if the path is illegal
+    """
+    if path is None or path == '':
+        raise ValueError("illegal path '%s'" % path)
+    return path
+
+
+def format_path(p, quote_spaces=False):
+    """Format a path in utf8, quoting it if necessary."""
+    if '\n' in p:
+        import re
+        p = re.sub('\n', '\\n', p)
+        quote = True
+    else:
+        quote = p[0] == '"' or (quote_spaces and ' ' in p)
+    if quote:
+        extra = GIT_FAST_IMPORT_NEEDS_EXTRA_SPACE_AFTER_QUOTE and ' ' or ''
+        p = '"%s"%s' % (p, extra)
+    return p.encode('utf8')
+
+
+def format_who_when(fields):
+    """Format a tuple of name,email,secs-since-epoch,utc-offset-secs as a string."""
+    offset = fields[3]
+    if offset < 0:
+        offset_sign = '-'
+        offset = abs(offset)
+    else:
+        offset_sign = '+'
+    offset_hours = offset / 3600
+    offset_minutes = offset / 60 - offset_hours * 60
+    offset_str = "%s%02d%02d" % (offset_sign, offset_hours, offset_minutes)
+    name = fields[0]
+    if name == '':
+        sep = ''
+    else:
+        sep = ' '
+    if isinstance(name, unicode):
+        name = name.encode('utf8')
+    email = fields[1]
+    if isinstance(email, unicode):
+        email = email.encode('utf8')
+    result = "%s%s<%s> %d %s" % (name, sep, email, fields[2], offset_str)
+    return result
+
+
+def format_property(name, value):
+    """Format the name and value (both unicode) of a property as a string."""
+    utf8_name = name.encode('utf8')
+    if value is not None:
+        utf8_value = value.encode('utf8')
+        result = "property %s %d %s" % (utf8_name, len(utf8_value), utf8_value)
+    else:
+        result = "property %s" % (utf8_name,)
+    return result
diff --git a/git_remote_helpers/fastimport/dates.py b/git_remote_helpers/fastimport/dates.py
new file mode 100644
index 0000000000..f532b2e249
--- /dev/null
+++ b/git_remote_helpers/fastimport/dates.py
@@ -0,0 +1,79 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Date parsing routines.
+
+Each routine returns timestamp,timezone where
+
+* timestamp is seconds since epoch
+* timezone is the offset from UTC in seconds.
+"""
+
+
+import time
+
+from git_remote_helpers.fastimport import errors
+
+
+def parse_raw(s, lineno=0):
+    """Parse a date from a raw string.
+    
+    The format must be exactly "seconds-since-epoch offset-utc".
+    See the spec for details.
+    """
+    timestamp_str, timezone_str = s.split(' ', 1)
+    timestamp = float(timestamp_str)
+    timezone = _parse_tz(timezone_str, lineno)
+    return timestamp, timezone
+
+
+def _parse_tz(tz, lineno):
+    """Parse a timezone specification in the [+|-]HHMM format.
+
+    :return: the timezone offset in seconds.
+    """
+    # from git_repository.py in bzr-git
+    if len(tz) != 5:
+        raise errors.InvalidTimezone(lineno, tz)
+    sign = {'+': +1, '-': -1}[tz[0]]
+    hours = int(tz[1:3])
+    minutes = int(tz[3:])
+    return sign * 60 * (60 * hours + minutes)
+
+
+def parse_rfc2822(s, lineno=0):
+    """Parse a date from a rfc2822 string.
+    
+    See the spec for details.
+    """
+    raise NotImplementedError(parse_rfc2822)
+
+
+def parse_now(s, lineno=0):
+    """Parse a date from a string.
+
+    The format must be exactly "now".
+    See the spec for details.
+    """
+    return time.time(), 0
+
+
+# Lookup tabel of date parsing routines
+DATE_PARSERS_BY_NAME = {
+    'raw':      parse_raw,
+    'rfc2822':  parse_rfc2822,
+    'now':      parse_now,
+    }
diff --git a/git_remote_helpers/fastimport/errors.py b/git_remote_helpers/fastimport/errors.py
new file mode 100644
index 0000000000..b8cf26fd09
--- /dev/null
+++ b/git_remote_helpers/fastimport/errors.py
@@ -0,0 +1,182 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Exception classes for fastimport"""
+
+
+class FastImportError(StandardError):
+    """The base exception class for all import processing exceptions."""
+
+    _fmt = "Unknown Import Error"
+
+    def __str__(self):
+        return self._fmt % self.__dict__
+
+class ParsingError(FastImportError):
+    """The base exception class for all import processing exceptions."""
+
+    _fmt = "Unknown Import Parsing Error"
+
+    def __init__(self, filename, lineno):
+        FastImportError.__init__(self)
+        self.filename = filename
+        self.lineno = lineno
+
+    def __str__(self):
+        result = []
+        if self.filename:
+            result.append(self.filename)
+            result.append(", ")
+        result.append("line ")
+        result.append(str(self.lineno))
+        result.append(": ")
+        result.append(FastImportError.__str__(self))
+        return "".join(result)
+
+
+class MissingBytes(ParsingError):
+    """Raised when EOF encountered while expecting to find more bytes."""
+
+    _fmt = ("Unexpected EOF - expected %(expected)d bytes,"
+        " found %(found)d")
+
+    def __init__(self, filename, lineno, expected, found):
+        ParsingError.__init__(self, filename, lineno)
+        self.expected = expected
+        self.found = found
+
+
+class MissingTerminator(ParsingError):
+    """Raised when EOF encountered while expecting to find a terminator."""
+
+    _fmt = "Unexpected EOF - expected '%(terminator)s' terminator"
+
+    def __init__(self, filename, lineno, terminator):
+        ParsingError.__init__(self, filename, lineno)
+        self.terminator = terminator
+
+
+class InvalidCommand(ParsingError):
+    """Raised when an unknown command found."""
+
+    _fmt = ("Invalid command '%(cmd)s'")
+
+    def __init__(self, filename, lineno, cmd):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+
+
+class MissingSection(ParsingError):
+    """Raised when a section is required in a command but not present."""
+
+    _fmt = ("Command %(cmd)s is missing section %(section)s")
+
+    def __init__(self, filename, lineno, cmd, section):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+        self.section = section
+
+
+class BadFormat(ParsingError):
+    """Raised when a section is formatted incorrectly."""
+
+    _fmt = ("Bad format for section %(section)s in "
+            "command %(cmd)s: found '%(text)s'")
+
+    def __init__(self, filename, lineno, cmd, section, text):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+        self.section = section
+        self.text = text
+
+
+class InvalidTimezone(ParsingError):
+    """Raised when converting a string timezone to a seconds offset."""
+
+    _fmt = "Timezone %(timezone)r could not be converted.%(reason)s"
+
+    def __init__(self, filename, lineno, timezone, reason=None):
+        ParsingError.__init__(self, filename, lineno)
+        self.timezone = timezone
+        if reason:
+            self.reason = ' ' + reason
+        else:
+            self.reason = ''
+
+
+class UnknownDateFormat(FastImportError):
+    """Raised when an unknown date format is given."""
+
+    _fmt = ("Unknown date format '%(format)s'")
+
+    def __init__(self, format):
+        FastImportError.__init__(self)
+        self.format = format
+
+
+class MissingHandler(FastImportError):
+    """Raised when a processor can't handle a command."""
+
+    _fmt = ("Missing handler for command %(cmd)s")
+
+    def __init__(self, cmd):
+        FastImportError.__init__(self)
+        self.cmd = cmd
+
+
+class UnknownParameter(FastImportError):
+    """Raised when an unknown parameter is passed to a processor."""
+
+    _fmt = ("Unknown parameter - '%(param)s' not in %(knowns)s")
+
+    def __init__(self, param, knowns):
+        FastImportError.__init__(self)
+        self.param = param
+        self.knowns = knowns
+
+
+class BadRepositorySize(FastImportError):
+    """Raised when the repository has an incorrect number of revisions."""
+
+    _fmt = ("Bad repository size - %(found)d revisions found, "
+        "%(expected)d expected")
+
+    def __init__(self, expected, found):
+        FastImportError.__init__(self)
+        self.expected = expected
+        self.found = found
+
+
+class BadRestart(FastImportError):
+    """Raised when the import stream and id-map do not match up."""
+
+    _fmt = ("Bad restart - attempted to skip commit %(commit_id)s "
+        "but matching revision-id is unknown")
+
+    def __init__(self, commit_id):
+        FastImportError.__init__(self)
+        self.commit_id = commit_id
+
+
+class UnknownFeature(FastImportError):
+    """Raised when an unknown feature is given in the input stream."""
+
+    _fmt = ("Unknown feature '%(feature)s' - try a later importer or "
+        "an earlier data format")
+
+    def __init__(self, feature):
+        FastImportError.__init__(self)
+        self.feature = feature
diff --git a/git_remote_helpers/fastimport/head_tracker.py b/git_remote_helpers/fastimport/head_tracker.py
new file mode 100644
index 0000000000..ad6b48c8b8
--- /dev/null
+++ b/git_remote_helpers/fastimport/head_tracker.py
@@ -0,0 +1,47 @@
+
+
+class HeadTracker(object):
+    """
+    Keep track of the heads in a fastimport stream.
+    """
+    def __init__(self):
+        self.last_ref = None
+
+        # map git ref name (e.g. "refs/heads/master") to id of last
+        # commit with that ref
+        self.last_ids = {}
+
+        # the set of heads seen so far in the stream, as a mapping
+        # from commit id of the head to set of ref names
+        self.heads = {}
+
+    def track_heads(self, cmd):
+        """Track the repository heads given a CommitCommand.
+        
+        :param cmd: the CommitCommand
+        :return: the list of parents in terms of commit-ids
+        """
+        # Get the true set of parents
+        if cmd.from_ is not None:
+            parents = [cmd.from_]
+        else:
+            last_id = self.last_ids.get(cmd.ref)
+            if last_id is not None:
+                parents = [last_id]
+            else:
+                parents = []
+        parents.extend(cmd.merges)
+
+        # Track the heads
+        self.track_heads_for_ref(cmd.ref, cmd.id, parents)
+        return parents
+
+    def track_heads_for_ref(self, cmd_ref, cmd_id, parents=None):
+        if parents is not None:
+            for parent in parents:
+                if parent in self.heads:
+                    del self.heads[parent]
+        self.heads.setdefault(cmd_id, set()).add(cmd_ref)
+        self.last_ids[cmd_ref] = cmd_id
+        self.last_ref = cmd_ref
+    
diff --git a/git_remote_helpers/fastimport/helpers.py b/git_remote_helpers/fastimport/helpers.py
new file mode 100644
index 0000000000..3ce5a98e17
--- /dev/null
+++ b/git_remote_helpers/fastimport/helpers.py
@@ -0,0 +1,88 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Miscellaneous useful stuff."""
+
+import os
+
+def single_plural(n, single, plural):
+    """Return a single or plural form of a noun based on number."""
+    if n == 1:
+        return single
+    else:
+        return plural
+
+
+def invert_dict(d):
+    """Invert a dictionary with keys matching each value turned into a list."""
+    # Based on recipe from ASPN
+    result = {}
+    for k, v in d.iteritems():
+        keys = result.setdefault(v, [])
+        keys.append(k)
+    return result
+
+
+def invert_dictset(d):
+    """Invert a dictionary with keys matching a set of values, turned into lists."""
+    # Based on recipe from ASPN
+    result = {}
+    for k, c in d.iteritems():
+        for v in c:
+            keys = result.setdefault(v, [])
+            keys.append(k)
+    return result
+
+
+def _common_path_and_rest(l1, l2, common=[]):
+    # From http://code.activestate.com/recipes/208993/
+    if len(l1) < 1: return (common, l1, l2)
+    if len(l2) < 1: return (common, l1, l2)
+    if l1[0] != l2[0]: return (common, l1, l2)
+    return _common_path_and_rest(l1[1:], l2[1:], common+[l1[0]])
+
+
+def common_path(path1, path2):
+    """Find the common bit of 2 paths."""
+    return ''.join(_common_path_and_rest(path1, path2)[0])
+
+
+def common_directory(paths):
+    """Find the deepest common directory of a list of paths.
+    
+    :return: if no paths are provided, None is returned;
+      if there is no common directory, '' is returned;
+      otherwise the common directory with a trailing / is returned.
+    """
+    def get_dir_with_slash(path):
+        if path == '' or path.endswith('/'):
+            return path
+        else:
+            dirname, basename = os.path.split(path)
+            if dirname == '':
+                return dirname
+            else:
+                return dirname + '/'
+
+    if not paths:
+        return None
+    elif len(paths) == 1:
+        return get_dir_with_slash(paths[0])
+    else:
+        common = common_path(paths[0], paths[1])
+        for path in paths[2:]:
+            common = common_path(common, path)
+        return get_dir_with_slash(common)
diff --git a/git_remote_helpers/fastimport/idmapfile.py b/git_remote_helpers/fastimport/idmapfile.py
new file mode 100644
index 0000000000..7b4ccf4afe
--- /dev/null
+++ b/git_remote_helpers/fastimport/idmapfile.py
@@ -0,0 +1,65 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Routines for saving and loading the id-map file."""
+
+import os
+
+
+def save_id_map(filename, revision_ids):
+    """Save the mapping of commit ids to revision ids to a file.
+
+    Throws the usual exceptions if the file cannot be opened,
+    written to or closed.
+
+    :param filename: name of the file to save the data to
+    :param revision_ids: a dictionary of commit ids to revision ids.
+    """
+    f = open(filename, 'wb')
+    try:
+        for commit_id, rev_id in revision_ids.iteritems():
+            f.write("%s %s\n" % (commit_id, rev_id))
+        f.flush()
+    finally:
+        f.close()
+
+
+def load_id_map(filename):
+    """Load the mapping of commit ids to revision ids from a file.
+
+    If the file does not exist, an empty result is returned.
+    If the file does exists but cannot be opened, read or closed,
+    the normal exceptions are thrown.
+
+    NOTE: It is assumed that commit-ids do not have embedded spaces.
+
+    :param filename: name of the file to save the data to
+    :result: map, count where:
+      map = a dictionary of commit ids to revision ids;
+      count = the number of keys in map
+    """
+    result = {}
+    count = 0
+    if os.path.exists(filename):
+        f = open(filename)
+        try:
+            for line in f:
+                parts = line[:-1].split(' ', 1)
+                result[parts[0]] = parts[1]
+                count += 1
+        finally:
+            f.close()
+    return result, count
diff --git a/git_remote_helpers/fastimport/parser.py b/git_remote_helpers/fastimport/parser.py
new file mode 100644
index 0000000000..f9c2655913
--- /dev/null
+++ b/git_remote_helpers/fastimport/parser.py
@@ -0,0 +1,621 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import warnings
+
+"""Parser of import data into command objects.
+
+In order to reuse existing front-ends, the stream format is a subset of
+the one used by git-fast-import (as of the 1.5.4 release of git at least).
+The grammar is:
+
+  stream ::= cmd*;
+
+  cmd ::= new_blob
+        | new_commit
+        | new_tag
+        | reset_branch
+        | checkpoint
+        | progress
+        ;
+
+  new_blob ::= 'blob' lf
+    mark?
+    file_content;
+  file_content ::= data;
+
+  new_commit ::= 'commit' sp ref_str lf
+    mark?
+    ('author' sp name '<' email '>' when lf)?
+    'committer' sp name '<' email '>' when lf
+    commit_msg
+    ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
+    ('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
+    file_change*
+    lf?;
+  commit_msg ::= data;
+
+  file_change ::= file_clr
+    | file_del
+    | file_rnm
+    | file_cpy
+    | file_obm
+    | file_inm;
+  file_clr ::= 'deleteall' lf;
+  file_del ::= 'D' sp path_str lf;
+  file_rnm ::= 'R' sp path_str sp path_str lf;
+  file_cpy ::= 'C' sp path_str sp path_str lf;
+  file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
+  file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
+    data;
+
+  new_tag ::= 'tag' sp tag_str lf
+    'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
+    'tagger' sp name '<' email '>' when lf
+    tag_msg;
+  tag_msg ::= data;
+
+  reset_branch ::= 'reset' sp ref_str lf
+    ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
+    lf?;
+
+  checkpoint ::= 'checkpoint' lf
+    lf?;
+
+  progress ::= 'progress' sp not_lf* lf
+    lf?;
+
+     # note: the first idnum in a stream should be 1 and subsequent
+     # idnums should not have gaps between values as this will cause
+     # the stream parser to reserve space for the gapped values.  An
+     # idnum can be updated in the future to a new object by issuing
+     # a new mark directive with the old idnum.
+     #
+  mark ::= 'mark' sp idnum lf;
+  data ::= (delimited_data | exact_data)
+    lf?;
+
+    # note: delim may be any string but must not contain lf.
+    # data_line may contain any data but must not be exactly
+    # delim. The lf after the final data_line is included in
+    # the data.
+  delimited_data ::= 'data' sp '<<' delim lf
+    (data_line lf)*
+    delim lf;
+
+     # note: declen indicates the length of binary_data in bytes.
+     # declen does not include the lf preceeding the binary data.
+     #
+  exact_data ::= 'data' sp declen lf
+    binary_data;
+
+     # note: quoted strings are C-style quoting supporting \c for
+     # common escapes of 'c' (e..g \n, \t, \\, \") or \nnn where nnn
+     # is the signed byte value in octal.  Note that the only
+     # characters which must actually be escaped to protect the
+     # stream formatting is: \, \" and LF.  Otherwise these values
+     # are UTF8.
+     #
+  ref_str     ::= ref;
+  sha1exp_str ::= sha1exp;
+  tag_str     ::= tag;
+  path_str    ::= path    | '"' quoted(path)    '"' ;
+  mode        ::= '100644' | '644'
+                | '100755' | '755'
+                | '120000'
+                ;
+
+  declen ::= # unsigned 32 bit value, ascii base10 notation;
+  bigint ::= # unsigned integer value, ascii base10 notation;
+  binary_data ::= # file content, not interpreted;
+
+  when         ::= raw_when | rfc2822_when;
+  raw_when     ::= ts sp tz;
+  rfc2822_when ::= # Valid RFC 2822 date and time;
+
+  sp ::= # ASCII space character;
+  lf ::= # ASCII newline (LF) character;
+
+     # note: a colon (':') must precede the numerical value assigned to
+     # an idnum.  This is to distinguish it from a ref or tag name as
+     # GIT does not permit ':' in ref or tag strings.
+     #
+  idnum   ::= ':' bigint;
+  path    ::= # GIT style file path, e.g. \"a/b/c\";
+  ref     ::= # GIT ref name, e.g. \"refs/heads/MOZ_GECKO_EXPERIMENT\";
+  tag     ::= # GIT tag name, e.g. \"FIREFOX_1_5\";
+  sha1exp ::= # Any valid GIT SHA1 expression;
+  hexsha1 ::= # SHA1 in hexadecimal format;
+
+     # note: name and email are UTF8 strings, however name must not
+     # contain '<' or lf and email must not contain any of the
+     # following: '<', '>', lf.
+     #
+  name  ::= # valid GIT author/committer name;
+  email ::= # valid GIT author/committer email;
+  ts    ::= # time since the epoch in seconds, ascii base10 notation;
+  tz    ::= # GIT style timezone;
+
+     # note: comments may appear anywhere in the input, except
+     # within a data command.  Any form of the data command
+     # always escapes the related input from comment processing.
+     #
+     # In case it is not clear, the '#' that starts the comment
+     # must be the first character on that the line (an lf have
+     # preceeded it).
+     #
+  comment ::= '#' not_lf* lf;
+  not_lf  ::= # Any byte that is not ASCII newline (LF);
+"""
+
+
+import re
+import sys
+
+from git_remote_helpers.fastimport import (
+    commands,
+    dates,
+    errors
+    )
+
+
+## Stream parsing ##
+
+class LineBasedParser(object):
+
+    def __init__(self, input, filename=None):
+        """A Parser that keeps track of line numbers.
+
+        :param input: the file-like object to read from
+        """
+        self.input = input
+        if filename is None:
+            try:
+                self.filename = input.name
+            except AttributeError:
+                self.filename = "(unknown)"
+        else:
+            self.filename = filename
+        self.lineno = 0
+        # Lines pushed back onto the input stream
+        self._buffer = []
+
+    def abort(self, exception, *args):
+        """Raise an exception providing line number information."""
+        raise exception(self.filename, self.lineno, *args)
+
+    def readline(self):
+        """Get the next line including the newline or '' on EOF."""
+        self.lineno += 1
+        if self._buffer:
+            return self._buffer.pop()
+        else:
+            return self.input.readline()
+
+    def next_line(self):
+        """Get the next line without the newline or None on EOF."""
+        line = self.readline()
+        if line:
+            return line[:-1]
+        else:
+            return None
+
+    def push_line(self, line):
+        """Push line back onto the line buffer.
+        
+        :param line: the line with no trailing newline
+        """
+        self.lineno -= 1
+        self._buffer.append(line + "\n")
+
+    def read_bytes(self, count):
+        """Read a given number of bytes from the input stream.
+        
+        Throws MissingBytes if the bytes are not found.
+
+        Note: This method does not read from the line buffer.
+
+        :return: a string
+        """
+        result = self.input.read(count)
+        found = len(result)
+        self.lineno += result.count("\n")
+        if found != count:
+            self.abort(errors.MissingBytes, count, found)
+        return result
+
+    def read_until(self, terminator):
+        """Read the input stream until the terminator is found.
+        
+        Throws MissingTerminator if the terminator is not found.
+
+        Note: This method does not read from the line buffer.
+
+        :return: the bytes read up to but excluding the terminator.
+        """
+        
+        lines = []
+        term = terminator + '\n'
+        while True:
+            line = self.input.readline()
+            if line == term:
+                break
+            else:
+                lines.append(line)
+        return ''.join(lines)
+
+
+# Regular expression used for parsing. (Note: The spec states that the name
+# part should be non-empty but git-fast-export doesn't always do that so
+# the first bit is \w*, not \w+.) Also git-fast-import code says the
+# space before the email is optional.
+_WHO_AND_WHEN_RE = re.compile(r'([^<]*)<(.*)> (.+)')
+_WHO_RE = re.compile(r'([^<]*)<(.*)>')
+
+
+class ImportParser(LineBasedParser):
+
+    def __init__(self, input, filename=None):
+        """A Parser of import commands.
+
+        :param input: the file-like object to read from
+        :param verbose: display extra information of not
+        """
+        LineBasedParser.__init__(self, input, filename)
+
+        # We auto-detect the date format when a date is first encountered
+        self.date_parser = None
+
+    def warning(self, msg):
+        sys.stderr.write("warning line %d: %s\n" % (self.lineno, msg))
+
+    def parse(self):
+        """Parse the input stream, yielding a sequence of ImportCommand
+        objects.  Iteration terminates on EOF.  Raises InvalidCommand on
+        parse error."""
+        while True:
+            line = self.next_line()
+            if line is None:
+                break
+            elif len(line) == 0 or line.startswith('#'):
+                continue
+            # Search for commands in order of likelihood
+            elif line.startswith('commit '):
+                yield self._parse_commit(line[len('commit '):])
+            elif line.startswith('blob'):
+                yield self._parse_blob()
+            elif line.startswith('done'):
+                break
+            elif line.startswith('progress '):
+                yield commands.ProgressCommand(line[len('progress '):])
+            elif line.startswith('reset '):
+                yield self._parse_reset(line[len('reset '):])
+            elif line.startswith('tag '):
+                yield self._parse_tag(line[len('tag '):])
+            elif line.startswith('checkpoint'):
+                yield commands.CheckpointCommand()
+            elif line.startswith('feature'):
+                yield self._parse_feature(line[len('feature '):])
+            else:
+                self.abort(errors.InvalidCommand, line)
+
+    def iter_commands(self):
+        warnings.warn("iter_commands() deprecated: use parse()",
+                      DeprecationWarning, stacklevel=2)
+        return self.parse()
+
+    def iter_file_commands(self):
+        """Iterator returning FileCommand objects.
+        
+        If an invalid file command is found, the line is silently
+        pushed back and iteration ends.
+        """
+        while True:
+            line = self.next_line()
+            if line is None:
+                break
+            elif len(line) == 0 or line.startswith('#'):
+                continue
+            # Search for file commands in order of likelihood
+            elif line.startswith('M '):
+                yield self._parse_file_modify(line[2:])
+            elif line.startswith('D '):
+                path = self._path(line[2:])
+                yield commands.FileDeleteCommand(path)
+            elif line.startswith('R '):
+                old, new = self._path_pair(line[2:])
+                yield commands.FileRenameCommand(old, new)
+            elif line.startswith('C '):
+                src, dest = self._path_pair(line[2:])
+                yield commands.FileCopyCommand(src, dest)
+            elif line.startswith('deleteall'):
+                yield commands.FileDeleteAllCommand()
+            else:
+                self.push_line(line)
+                break
+
+    def _parse_blob(self):
+        """Parse a blob command."""
+        location = (self.filename, self.lineno)
+        mark = self._get_mark_if_any()
+        data = self._get_data('blob')
+        return commands.BlobCommand(mark, data, location)
+
+    def _parse_commit(self, ref):
+        """Parse a commit command."""
+        location = (self.filename, self.lineno)
+        mark = self._get_mark_if_any()
+        author = self._get_user_info('commit', 'author', False)
+        more_authors = []
+        while True:
+            another_author = self._get_user_info('commit', 'author', False)
+            if another_author is not None:
+                more_authors.append(another_author)
+            else:
+                break
+        committer = self._get_user_info('commit', 'committer')
+        message = self._get_data('commit', 'message')
+        try:
+            message = message.decode('utf_8')
+        except UnicodeDecodeError:
+            self.warning(
+                "commit message not in utf8 - replacing unknown characters")
+            message = message.decode('utf_8', 'replace')
+        from_ = self._get_from()
+        merges = []
+        while True:
+            merge = self._get_merge()
+            if merge is not None:
+                # while the spec suggests it's illegal, git-fast-export
+                # outputs multiple merges on the one line, e.g.
+                # merge :x :y :z
+                these_merges = merge.split(" ")
+                merges.extend(these_merges)
+            else:
+                break
+        properties = {}
+        while True:
+            name_value = self._get_property()
+            if name_value is not None:
+                name, value = name_value
+                properties[name] = value
+            else:
+                break
+        file_cmds = list(self.iter_file_commands())
+        return commands.CommitCommand(ref, mark, author, committer, message,
+            from_, merges, file_cmds, location,
+            more_authors=more_authors, properties=properties)
+
+    def _parse_feature(self, info):
+        """Parse a feature command."""
+        parts = info.split("=", 1)
+        name = parts[0]
+        if len(parts) > 1:
+            value = self._path(parts[1])
+        else:
+            value = None
+        location = (self.filename, self.lineno)
+        return commands.FeatureCommand(name, value, location=location)
+
+
+    def _parse_file_modify(self, info):
+        """Parse a filemodify command within a commit.
+
+        :param info: a string in the format "mode dataref path"
+          (where dataref might be the hard-coded literal 'inline').
+        """
+        params = info.split(' ', 2)
+        path = self._path(params[2])
+        mode = params[0]
+        if params[1] == 'inline':
+            dataref = None
+            data = self._get_data('filemodify')
+        else:
+            dataref = params[1]
+            data = None
+        return commands.FileModifyCommand(path, mode, dataref, data)
+
+    def _parse_reset(self, ref):
+        """Parse a reset command."""
+        from_ = self._get_from()
+        return commands.ResetCommand(ref, from_)
+
+    def _parse_tag(self, name):
+        """Parse a tag command."""
+        from_ = self._get_from('tag')
+        tagger = self._get_user_info('tag', 'tagger', accept_just_who=True)
+        message = self._get_data('tag', 'message').decode('utf_8')
+        return commands.TagCommand(name, from_, tagger, message)
+
+    def _get_mark_if_any(self):
+        """Parse a mark section."""
+        line = self.next_line()
+        if line.startswith('mark :'):
+            return line[len('mark :'):]
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_from(self, required_for=None):
+        """Parse a from section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('from '):
+            return line[len('from '):]
+        elif required_for:
+            self.abort(errors.MissingSection, required_for, 'from')
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_merge(self):
+        """Parse a merge section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('merge '):
+            return line[len('merge '):]
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_property(self):
+        """Parse a property section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('property '):
+            return self._name_value(line[len('property '):])
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_user_info(self, cmd, section, required=True,
+        accept_just_who=False):
+        """Parse a user section."""
+        line = self.next_line()
+        if line.startswith(section + ' '):
+            return self._who_when(line[len(section + ' '):], cmd, section,
+                accept_just_who=accept_just_who)
+        elif required:
+            self.abort(errors.MissingSection, cmd, section)
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_data(self, required_for, section='data'):
+        """Parse a data section."""
+        line = self.next_line()
+        if line.startswith('data '):
+            rest = line[len('data '):]
+            if rest.startswith('<<'):
+                return self.read_until(rest[2:])
+            else:
+                size = int(rest)
+                read_bytes = self.read_bytes(size)
+                # optional LF after data.
+                next = self.input.readline()
+                self.lineno += 1
+                if len(next) > 1 or next != "\n":
+                    self.push_line(next[:-1])
+                return read_bytes
+        else:
+            self.abort(errors.MissingSection, required_for, section)
+
+    def _who_when(self, s, cmd, section, accept_just_who=False):
+        """Parse who and when information from a string.
+        
+        :return: a tuple of (name,email,timestamp,timezone). name may be
+            the empty string if only an email address was given.
+        """
+        match = _WHO_AND_WHEN_RE.search(s)
+        if match:
+            datestr = match.group(3)
+            if self.date_parser is None:
+                # auto-detect the date format
+                if len(datestr.split(' ')) == 2:
+                    format = 'raw'
+                elif datestr == 'now':
+                    format = 'now'
+                else:
+                    format = 'rfc2822'
+                self.date_parser = dates.DATE_PARSERS_BY_NAME[format]
+            when = self.date_parser(datestr, self.lineno)
+        else:
+            match = _WHO_RE.search(s)
+            if accept_just_who and match:
+                # HACK around missing time
+                # TODO: output a warning here
+                when = dates.DATE_PARSERS_BY_NAME['now']('now')
+            else:
+                self.abort(errors.BadFormat, cmd, section, s)
+
+        # Do not attempt to decode name or email address; they are just
+        # bytes.  (Everything will work out better if they are in UTF-8,
+        # but that's not guaranteed.)
+        name = match.group(1).rstrip()
+        email = match.group(2)
+        return (name, email, when[0], when[1])
+
+    def _name_value(self, s):
+        """Parse a (name,value) tuple from 'name value-length value'."""
+        parts = s.split(' ', 2)
+        name = parts[0]
+        if len(parts) == 1:
+            value = None
+        else:
+            size = int(parts[1])
+            value = parts[2]
+            still_to_read = size - len(value)
+            if still_to_read == 1:
+                value += "\n"
+            elif still_to_read > 0:
+                read_bytes = self.read_bytes(still_to_read - 1)
+                value += "\n" + read_bytes
+            value = value.decode('utf8')
+        return (name, value)
+
+    def _path(self, s):
+        """Parse a path."""
+        if s.startswith('"'):
+            if s[-1] != '"':
+                self.abort(errors.BadFormat, '?', '?', s)
+            else:
+                return _unquote_c_string(s[1:-1])
+
+        # Do *not* decode the path to a Unicode string: filenames on
+        # Unix are just bytes.  Git and Mercurial, at least, inherit
+        # this stance.  git-fast-import(1) merely says "It is
+        # recommended that  always be encoded using UTF-8.", which
+        # is good advice ... but not something we can count on here.
+        return s
+
+    def _path_pair(self, s):
+        """Parse two paths separated by a space."""
+        # TODO: handle a space in the first path
+        if s.startswith('"'):
+            parts = s[1:].split('" ', 1)
+        else:
+            parts = s.split(' ', 1)
+        if len(parts) != 2:
+            self.abort(errors.BadFormat, '?', '?', s)
+        elif parts[1].startswith('"') and parts[1].endswith('"'):
+            parts[1] = parts[1][1:-1]
+        elif parts[1].startswith('"') or parts[1].endswith('"'):
+            self.abort(errors.BadFormat, '?', '?', s)
+        return map(_unquote_c_string, parts)
+
+    def _mode(self, s):
+        """Parse a file mode into executable and symlink flags.
+        
+        :return (is_executable, is_symlink)
+        """
+        # Note: Output from git-fast-export slightly different to spec
+        if s in ['644', '100644', '0100644']:
+            return False, False
+        elif s in ['755', '100755', '0100755']:
+            return True, False
+        elif s in ['120000', '0120000']:
+            return False, True
+        else:
+            self.abort(errors.BadFormat, 'filemodify', 'mode', s)
+
+
+def _unquote_c_string(s):
+    """replace C-style escape sequences (\n, \", etc.) with real chars."""
+    # HACK: Python strings are close enough
+    return s.decode('string_escape', 'replace')
diff --git a/git_remote_helpers/fastimport/processor.py b/git_remote_helpers/fastimport/processor.py
new file mode 100644
index 0000000000..bfb4226a46
--- /dev/null
+++ b/git_remote_helpers/fastimport/processor.py
@@ -0,0 +1,222 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Processor of import commands.
+
+This module provides core processing functionality including an abstract class
+for basing real processors on. See the processors package for examples.
+"""
+
+import sys
+import time
+import logging
+
+from git_remote_helpers.fastimport import errors
+
+log = logging.getLogger(__name__)
+
+
+class ImportProcessor(object):
+    """Base class for import processors.
+    
+    Subclasses should override the pre_*, post_* and *_handler
+    methods as appropriate.
+    """
+
+    known_params = []
+
+    def __init__(self, params=None, verbose=False, outf=None):
+        if outf is None:
+            self.outf = sys.stdout
+        else:
+            self.outf = outf
+        self.verbose = verbose
+        if params is None:
+            self.params = {}
+        else:
+            self.params = params
+            self.validate_parameters()
+
+        # Handlers can set this to request exiting cleanly without
+        # iterating through the remaining commands
+        self.finished = False
+
+    def validate_parameters(self):
+        """Validate that the parameters are correctly specified."""
+        for p in self.params:
+            if p not in self.known_params:
+                raise errors.UnknownParameter(p, self.known_params)
+
+    def process(self, commands):
+        """Process a stream of fast-import commands from a parser.
+
+        :param commands: a sequence of commands.ImportCommand objects
+        """
+        self.pre_process()
+        for cmd in commands:
+            try:
+                handler = self.__class__.__dict__[cmd.name + "_handler"]
+            except KeyError:
+                raise errors.MissingHandler(cmd.name)
+            else:
+                self.pre_handler(cmd)
+                handler(self, cmd)
+                self.post_handler(cmd)
+            if self.finished:
+                break
+        self.post_process()
+
+    def pre_process(self):
+        """Hook for logic at start of processing.
+
+        Called just before process() starts iterating over its sequence
+        of commands.
+        """
+        pass
+
+    def post_process(self):
+        """Hook for logic at end of successful processing.
+
+        Called after process() finishes successfully iterating over its
+        sequence of commands (i.e. not called if an exception is raised
+        while processing commands).
+        """
+        pass
+
+    def pre_handler(self, cmd):
+        """Hook for logic before each handler starts."""
+        pass
+
+    def post_handler(self, cmd):
+        """Hook for logic after each handler finishes."""
+        pass
+
+    def progress_handler(self, cmd):
+        """Process a ProgressCommand."""
+        raise NotImplementedError(self.progress_handler)
+
+    def blob_handler(self, cmd):
+        """Process a BlobCommand."""
+        raise NotImplementedError(self.blob_handler)
+
+    def checkpoint_handler(self, cmd):
+        """Process a CheckpointCommand."""
+        raise NotImplementedError(self.checkpoint_handler)
+
+    def commit_handler(self, cmd):
+        """Process a CommitCommand."""
+        raise NotImplementedError(self.commit_handler)
+
+    def reset_handler(self, cmd):
+        """Process a ResetCommand."""
+        raise NotImplementedError(self.reset_handler)
+
+    def tag_handler(self, cmd):
+        """Process a TagCommand."""
+        raise NotImplementedError(self.tag_handler)
+
+    def feature_handler(self, cmd):
+        """Process a FeatureCommand."""
+        raise NotImplementedError(self.feature_handler)
+
+
+class CommitHandler(object):
+    """Base class for commit handling.
+    
+    Subclasses should override the pre_*, post_* and *_handler
+    methods as appropriate.
+    """
+
+    def __init__(self, command):
+        self.command = command
+
+    def process(self):
+        self.pre_process_files()
+        for fc in self.command.file_cmds:
+            try:
+                handler = self.__class__.__dict__[fc.name[4:] + "_handler"]
+            except KeyError:
+                raise errors.MissingHandler(fc.name)
+            else:
+                handler(self, fc)
+        self.post_process_files()
+
+    def _log(self, level, msg, *args):
+        log.log(level, msg + " (%s)", *(args + (self.command.id,)))
+
+    # Logging methods: unused in this library, but used by
+    # bzr-fastimport.  Could be useful for other subclasses.
+
+    def note(self, msg, *args):
+        """log.info() with context about the command"""
+        self._log(logging.INFO, msg, *args)
+
+    def warning(self, msg, *args):
+        """log.warning() with context about the command"""
+        self._log(logging.WARNING, msg, *args)
+
+    def debug(self, msg, *args):
+        """log.debug() with context about the command"""
+        self._log(logging.DEBUG, msg, *args)
+
+    def pre_process_files(self):
+        """Prepare for committing."""
+        pass
+
+    def post_process_files(self):
+        """Save the revision."""
+        pass
+
+    def modify_handler(self, filecmd):
+        """Handle a filemodify command."""
+        raise NotImplementedError(self.modify_handler)
+
+    def delete_handler(self, filecmd):
+        """Handle a filedelete command."""
+        raise NotImplementedError(self.delete_handler)
+
+    def copy_handler(self, filecmd):
+        """Handle a filecopy command."""
+        raise NotImplementedError(self.copy_handler)
+
+    def rename_handler(self, filecmd):
+        """Handle a filerename command."""
+        raise NotImplementedError(self.rename_handler)
+
+    def deleteall_handler(self, filecmd):
+        """Handle a filedeleteall command."""
+        raise NotImplementedError(self.deleteall_handler)
+
+
+def parseMany(filenames, parser_factory, processor):
+    """Parse multiple input files, sending the results all to
+    'processor'.  parser_factory must be a callable that takes one input
+    file and returns an ImportParser instance, e.g. the ImportParser
+    class object itself.  Each file in 'filenames' is opened, parsed,
+    and closed in turn.  For filename \"-\", reads stdin.
+    """
+    for filename in filenames:
+        if filename == "-":
+            infile = sys.stdin
+        else:
+            infile = open(filename, "rb")
+
+        try:
+            parser = parser_factory(infile)
+            processor.process(parser.parse())
+        finally:
+            if filename != "-":
+                infile.close()
diff --git a/git_remote_helpers/setup.py b/git_remote_helpers/setup.py
index 4d434b65cb..a19c061fdf 100644
--- a/git_remote_helpers/setup.py
+++ b/git_remote_helpers/setup.py
@@ -13,5 +13,6 @@ setup(
     author_email = 'git@vger.kernel.org',
     url = 'http://www.git-scm.com/',
     package_dir = {'git_remote_helpers': ''},
-    packages = ['git_remote_helpers', 'git_remote_helpers.git'],
+    packages = ['git_remote_helpers', 'git_remote_helpers.git',
+                'git_remote_helpers.fastimport'],
 )

From f75cf8d753ebdcff6ea49dbd983be65f2feb3b65 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:05:53 +0200
Subject: [PATCH 3439/3720] git-remote-hg: add hgimport, an hg-fast-import
 equivalent

This class will be used by git-remote-hg to do the heavy lifting.
---
 git_remote_helpers/hg/hgimport.py | 401 ++++++++++++++++++++++++++++++
 1 file changed, 401 insertions(+)
 create mode 100644 git_remote_helpers/hg/hgimport.py

diff --git a/git_remote_helpers/hg/hgimport.py b/git_remote_helpers/hg/hgimport.py
new file mode 100644
index 0000000000..36fee8e96b
--- /dev/null
+++ b/git_remote_helpers/hg/hgimport.py
@@ -0,0 +1,401 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Processor of import commands.
+
+This module provides core processing functionality including an abstract class
+for basing real processors on. See the processors package for examples.
+"""
+
+import os
+import shutil
+
+from mercurial import context
+from mercurial.node import nullid, hex
+
+from git_remote_helpers.util import die
+from git_remote_helpers.fastimport import processor, parser
+
+
+class commit(object):
+    def __init__(self, author, date, desc, parents, branch=None, rev=None,
+                 extra={}, sortkey=None):
+        self.author = author or 'unknown'
+        self.date = date or '0 0'
+        self.desc = desc
+        self.parents = parents
+        self.branch = branch
+        self.rev = rev
+        self.extra = extra
+        self.sortkey = sortkey
+
+
+class HgImportProcessor(processor.ImportProcessor):
+
+    def __init__(self, ui, repo):
+        super(HgImportProcessor, self).__init__()
+        self.ui = ui
+        self.repo = repo
+
+        self.branchnames = True
+
+        self.idmap = {}
+        self.commitmap = {}             # map commit ID (":1") to commit object
+        self.branchmap = {}             # map branch name to list of heads
+
+        self.tags = []                  # list of (tag, mark) tuples
+
+        self.numblobs = 0               # for progress reporting
+        self.blobdir = None
+
+    def setup(self):
+        """Setup before processing any streams."""
+        pass
+
+    def teardown(self):
+        """Cleanup after processing all streams."""
+        if self.blobdir and os.path.exists(self.blobdir):
+            self.ui.status("Removing blob dir %r ...\n" % self.blobdir)
+            shutil.rmtree(self.blobdir)
+
+    def load_marksfile(self, name):
+        try:
+            f = open(name)
+            lines = f.readlines()
+            f.close()
+            parsed = [i.strip().split(' ') for i in lines]
+            self.idmap = dict((i[0], i[1]) for i in parsed)
+        except IOError, e:
+            die("load: %s", str(e))
+
+    def write_marksfile(self, name):
+        try:
+            f = open(name, "w")
+            for pair in sorted(self.idmap.iteritems()):
+                f.write("%s %s\n" % pair)
+            f.close()
+        except IOError, e:
+            die("write: %s", str(e))
+
+    def progress_handler(self, cmd):
+        self.ui.write("Progress: %s\n" % cmd.message)
+
+    def blob_handler(self, cmd):
+        self.writeblob(cmd.id, cmd.data)
+
+    def _getblobfilename(self, blobid):
+        if self.blobdir is None:
+            raise RuntimeError("no blobs seen, so no blob directory created")
+        # XXX should escape ":" for windows
+        return os.path.join(self.blobdir, "blob-" + blobid)
+
+    def getblob(self, fileid):
+        (commitid, blobid) = fileid
+        f = open(self._getblobfilename(blobid), "rb")
+        try:
+            return f.read()
+        finally:
+            f.close()
+
+    def writeblob(self, blobid, data):
+        if self.blobdir is None:        # no blobs seen yet
+            self.blobdir = os.path.join(self.repo.root, ".hg", "blobs")
+            if not os.path.exists(self.blobdir):
+                os.mkdir(self.blobdir)
+
+        fn = self._getblobfilename(blobid)
+        blobfile = open(fn, "wb")
+        #self.ui.debug("writing blob %s to %s (%d bytes)\n"
+        #              % (blobid, fn, len(data)))
+        blobfile.write(data)
+        blobfile.close()
+
+        self.numblobs += 1
+        if self.numblobs % 500 == 0:
+            self.ui.status("%d blobs read\n" % self.numblobs)
+
+    def getmode(self, name, fileid):
+        (commitid, blobid) = fileid
+        return self.filemodes[commitid][name]
+
+    def checkpoint_handler(self, cmd):
+        # This command means nothing to us
+        pass
+
+    def _getcommit(self, committish):
+        """Given a mark reference or a branch name, return the
+        appropriate commit object.  Return None if committish is a
+        branch with no commits.  Raises KeyError if anything else is out
+        of whack.
+        """
+        if committish.startswith(":"):
+            # KeyError here indicates the input stream is broken.
+            return self.commitmap[committish]
+        else:
+            branch = self._getbranch(committish)
+            if branch is None:
+                raise ValueError("invalid committish: %r" % committish)
+
+            heads = self.branchmap.get(branch)
+            if heads is None:
+                return None
+            else:
+                # KeyError here indicates bad commit id in self.branchmap.
+                return self.commitmap[heads[-1]]
+
+    def _getbranch(self, ref):
+        """Translate a Git head ref to corresponding Mercurial branch
+        name.  E.g. \"refs/heads/foo\" is translated to \"foo\".
+        Special case: \"refs/heads/master\" becomes \"default\".  If
+        'ref' is not a head ref, return None.
+        """
+        prefix = "refs/heads/"
+        if ref.startswith(prefix):
+            branch = ref[len(prefix):]
+            if branch == "master":
+                return "default"
+            else:
+                return branch
+        else:
+            return None
+
+    def commit_handler(self, cmd):
+        # XXX this assumes the fixup branch name used by cvs2git.  In
+        # contrast, git-fast-import(1) recommends "TAG_FIXUP" (not under
+        # refs/heads), and implies that it can be called whatever the
+        # creator of the fastimport dump wants to call it.  So the name
+        # of the fixup branch should be configurable!
+        fixup = (cmd.ref == "refs/heads/TAG.FIXUP")
+
+        if cmd.from_:
+            first_parent = cmd.from_
+        else:
+            first_parent = self._getcommit(cmd.ref) # commit object
+            if first_parent is not None:
+                first_parent = first_parent.rev     # commit id
+
+        if cmd.merges:
+            if len(cmd.merges) > 1:
+                raise NotImplementedError("Can't handle more than two parents")
+            second_parent = cmd.merges[0]
+        else:
+            second_parent = None
+
+        if first_parent is None and second_parent is not None:
+            # First commit on a new branch that has 'merge' but no 'from':
+            # special case meaning branch starts with no files; the contents of
+            # the first commit (this one) determine the list of files at branch
+            # time.
+            first_parent = second_parent
+            second_parent = None
+            no_files = True             # XXX this is ignored...
+
+        self.ui.debug("commit %s: first_parent = %r, second_parent = %r\n"
+                      % (cmd, first_parent, second_parent))
+        assert ((first_parent != second_parent) or
+                (first_parent is second_parent is None)), \
+               ("commit %s: first_parent == second parent = %r"
+                % (cmd, first_parent))
+
+        # Figure out the Mercurial branch name.
+        if fixup and first_parent is not None:
+            # If this is a fixup commit, pretend it happened on the same
+            # branch as its first parent.  (We don't want a Mercurial
+            # named branch called "TAG.FIXUP" in the output repository.)
+            branch = self.commitmap[first_parent].branch
+        else:
+            branch = self._getbranch(cmd.ref)
+
+        commit_handler = HgImportCommitHandler(
+            self, cmd, self.ui)
+        commit_handler.process()
+        modified = dict(commit_handler.modified)
+        modes = commit_handler.mode
+        copies = commit_handler.copies
+
+        # in case we are converting from git or bzr, prefer author but
+        # fallback to committer (committer is required, author is
+        # optional)
+        userinfo = cmd.author or cmd.committer
+        if userinfo[0] == userinfo[1]:
+            # In order to conform to fastimport syntax, cvs2git with no
+            # authormap produces author names like "jsmith "; if
+            # we see that, revert to plain old "jsmith".
+            user = userinfo[0]
+        else:
+            user = "%s <%s>" % (userinfo[0], userinfo[1])
+
+        assert type(cmd.message) is unicode
+        text = cmd.message.encode("utf-8")
+        date = self.convert_date(userinfo)
+
+        parents = [self.idmap[i] for i in first_parent, second_parent if i]
+        cmt = commit(user, date, text, parents, branch, rev=cmd.id)
+
+        self.commitmap[cmd.id] = cmt
+        heads = self.branchmap.get(branch)
+        if heads is None:
+            heads = [cmd.id]
+        else:
+            # adding to an existing branch: replace the previous head
+            try:
+                heads.remove(first_parent)
+            except ValueError:          # first parent not a head: no problem
+                pass
+            heads.append(cmd.id)        # at end means this is tipmost
+        self.branchmap[branch] = heads
+        self.ui.debug("processed commit %s\n" % cmd)
+
+        self.idmap[cmd.id] = self.putcommit(modified, modes, copies, cmt)
+
+    def putcommit(self, files, modes, copies, commit):
+
+        def getfilectx(repo, memctx, name):
+            fileid = files[name]
+            if fileid is None:  # deleted file
+                raise IOError
+            data = self.getblob(fileid)
+            ctx = context.memfilectx(name, data, 'l' in modes,
+                                     'x' in modes, copies.get(name))
+            return ctx
+
+        parents = list(set(commit.parents))
+        nparents = len(parents)
+
+        if len(parents) < 2:
+            parents.append(nullid)
+        if len(parents) < 2:
+            parents.append(nullid)
+        p2 = parents.pop(0)
+
+        text = commit.desc
+        extra = commit.extra.copy()
+        if self.branchnames and commit.branch:
+            extra['branch'] = commit.branch
+
+        while parents:
+            p1 = p2
+            p2 = parents.pop(0)
+            ctx = context.memctx(self.repo, (p1, p2), text, files.keys(),
+                                 getfilectx, commit.author, commit.date, extra)
+            self.repo.commitctx(ctx)
+            text = "(octopus merge fixup)\n"
+            p2 = hex(self.repo.changelog.tip())
+
+        return p2
+
+    def convert_date(self, c):
+        res = (int(c[2]), int(c[3]))
+        #print c, res
+        #print type((0, 0)), type(res), len(res), type(res) is type((0, 0))
+        #if type(res) is type((0, 0)) and len(res) == 2:
+        #    print "go for it"
+        #return res
+        return "%d %d" % res
+
+    def reset_handler(self, cmd):
+        tagprefix = "refs/tags/"
+        branch = self._getbranch(cmd.ref)
+        if branch:
+            # The usual case for 'reset': (re)create the named branch.
+            # XXX what should we do if cmd.from_ is None?
+            if cmd.from_ is not None:
+                self.branchmap[branch] = [cmd.from_]
+            else:
+                # pretend the branch never existed... is this right?!?
+                try:
+                    del self.branchmap[branch]
+                except KeyError:
+                    pass
+            #else:
+            #    # XXX filename? line number?
+            #    self.ui.warn("ignoring branch reset with no 'from'\n")
+        elif cmd.ref.startswith(tagprefix):
+            # Create a "lightweight tag" in Git terms.  As I understand
+            # it, that's a tag with no description and no history --
+            # rather like CVS tags.  cvs2git turns CVS tags into Git
+            # lightweight tags, so we should make sure they become
+            # Mercurial tags.  But we don't have to fake a history for
+            # them; save them up for the end.
+            tag = cmd.ref[len(tagprefix):]
+            self.tags.append((tag, cmd.from_))
+
+    def tag_handler(self, cmd):
+        pass
+
+    def feature_handler(self, cmd):
+        if cmd.feature_name == 'done':
+            return
+        raise NotImplementedError(self.feature_handler)
+
+
+class HgImportCommitHandler(processor.CommitHandler):
+
+    def __init__(self, parent, command, ui):
+        self.parent = parent            # HgImportProcessor running the show
+        self.command = command          # CommitCommand that we're processing
+        self.ui = ui
+
+        # Files changes by this commit as a list of (filename, id)
+        # tuples where id is (commitid, blobid).  The blobid is
+        # needed to fetch the file's contents later, and the commitid
+        # is needed to fetch the mode.
+        # (XXX what about inline file contents?)
+        # (XXX how to describe deleted files?)
+        self.modified = []
+
+        # mode of files listed in self.modified: '', 'x', or 'l'
+        self.mode = {}
+
+        # dictionary of src: dest (renamed files are in here and self.modified)
+        self.copies = {}
+
+        # number of inline files seen in this commit
+        self.inlinecount = 0
+
+    def modify_handler(self, filecmd):
+        if filecmd.dataref:
+            blobid = filecmd.dataref    # blobid is the mark of the blob
+        else:
+            blobid = "%s-inline:%d" % (self.command.id, self.inlinecount)
+            assert filecmd.data is not None
+            self.parent.writeblob(blobid, filecmd.data)
+            self.inlinecount += 1
+
+        fileid = (self.command.id, blobid)
+
+        self.modified.append((filecmd.path, fileid))
+        if filecmd.mode.endswith("644"): # normal file
+            mode = ''
+        elif filecmd.mode.endswith("755"): # executable
+            mode = 'x'
+        elif filecmd.mode == "120000":  # symlink
+            mode = 'l'
+        else:
+            raise RuntimeError("mode %r unsupported" % filecmd.mode)
+
+        self.mode[filecmd.path] = mode
+
+    def delete_handler(self, filecmd):
+        self.modified.append((filecmd.path, None))
+
+    def copy_handler(self, filecmd):
+        self.copies[filecmd.src_path] = filecmd.dest_path
+
+    def rename_handler(self, filecmd):
+        # copy oldname to newname and delete oldname
+        self.copies[filecmd.oldname] = filecmd.newname
+        self.files.append((filecmd.path, None))

From 7ae2109f76cb7d827e1d2a10100706cd177ce66a Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:12:27 +0200
Subject: [PATCH 3440/3720] git-remote-hg: add GitHg, a helper class for
 converting hg commits to git

This class will be used by HgExport.
---
 git_remote_helpers/hg/hg.py | 116 ++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 git_remote_helpers/hg/hg.py

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
new file mode 100644
index 0000000000..758ba242d8
--- /dev/null
+++ b/git_remote_helpers/hg/hg.py
@@ -0,0 +1,116 @@
+import urllib
+import re
+
+class GitHg(object):
+    """Class that handles various aspects of converting a hg commit to git.
+    """
+
+    def __init__(self, warn):
+        """Initializes a new GitHg object with the specified warner.
+        """
+
+        self.warn = warn
+
+    def format_timezone(self, offset):
+        if offset % 60 != 0:
+            raise ValueError("Unable to handle non-minute offset.")
+        sign = (offset < 0) and '-' or '+'
+        offset = abs(offset)
+        return '%c%02d%02d' % (sign, offset / 3600, (offset / 60) % 60)
+
+    def get_committer(self, ctx):
+        extra = ctx.extra()
+
+        if 'committer' in extra:
+            # fixup timezone
+            (name_timestamp, timezone) = extra['committer'].rsplit(' ', 1)
+            try:
+                timezone = self.format_timezone(-int(timezone))
+                return '%s %s' % (name_timestamp, timezone)
+            except ValueError:
+                self.warn("Ignoring committer in extra, invalid timezone in r%s: '%s'.\n" % (ctx.rev(), timezone))
+
+        return None
+
+    def get_message(self, ctx):
+        extra = ctx.extra()
+
+        message = ctx.description() + "\n"
+        if 'message' in extra:
+            message = apply_delta(message, extra['message'])
+
+        # HG EXTRA INFORMATION
+        add_extras = False
+        extra_message = ''
+        if not ctx.branch() == 'default':
+            add_extras = True
+            extra_message += "branch : " + ctx.branch() + "\n"
+
+        renames = []
+        for f in ctx.files():
+            if f not in ctx.manifest():
+                continue
+            rename = ctx.filectx(f).renamed()
+            if rename:
+                renames.append((rename[0], f))
+
+        if renames:
+            add_extras = True
+            for oldfile, newfile in renames:
+                extra_message += "rename : " + oldfile + " => " + newfile + "\n"
+
+        for key, value in extra.iteritems():
+            if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'):
+                continue
+            else:
+                add_extras = True
+                extra_message += "extra : " + key + " : " +  urllib.quote(value) + "\n"
+
+        if add_extras:
+            message += "\n--HG--\n" + extra_message
+
+        return message
+
+    def get_author(self, ctx):
+        # hg authors might not have emails
+        author = ctx.user()
+
+        # check for git author pattern compliance
+        regex = re.compile('^(.*?) \<(.*?)\>(.*)$')
+        a = regex.match(author)
+
+        if a:
+            name = a.group(1)
+            email = a.group(2)
+            if len(a.group(3)) > 0:
+                name += ' ext:(' + urllib.quote(a.group(3)) + ')'
+            author = name + ' <' + email + '>'
+        else:
+            author = author + ' '
+
+        if 'author' in ctx.extra():
+            author = apply_delta(author, ctx.extra()['author'])
+
+        (time, timezone) = ctx.date()
+        date = str(int(time)) + ' ' + self.format_timezone(-timezone)
+
+        return author + ' ' + date
+
+    def get_parents(self, ctx):
+        def is_octopus_part(ctx):
+            return ctx.extra().get('hg-git', None) in ('octopus', 'octopus-done')
+
+        parents = []
+        if ctx.extra().get('hg-git', None) == 'octopus-done':
+            # implode octopus parents
+            part = ctx
+            while is_octopus_part(part):
+                (p1, p2) = part.parents()
+                assert not is_octopus_part(p1)
+                parents.append(p1)
+                part = p2
+            parents.append(p2)
+        else:
+            parents = ctx.parents()
+
+        return parents

From c680182d661d3d8465dbe84676dfe4ffc266fb86 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:37:06 +0200
Subject: [PATCH 3441/3720] git-remote-hg: add hgexport, an hg-fast-export
 equivalent

This class will be used by git-remote-hg to do the heavy lifting.
---
 git_remote_helpers/hg/hgexport.py | 280 ++++++++++++++++++++++++++++++
 1 file changed, 280 insertions(+)
 create mode 100644 git_remote_helpers/hg/hgexport.py

diff --git a/git_remote_helpers/hg/hgexport.py b/git_remote_helpers/hg/hgexport.py
new file mode 100644
index 0000000000..8a255a45d2
--- /dev/null
+++ b/git_remote_helpers/hg/hgexport.py
@@ -0,0 +1,280 @@
+import binascii
+import os.path
+import sys
+
+
+LF = '\n'
+SP = ' '
+
+
+class HgExportGenerator(object):
+    def __init__(self, repo):
+        self.git_hg = repo.git_hg
+        self.repo = repo
+        self.prefix = repo.prefix
+        self.nullref = "0" * 40
+        self.next_id = 0
+        self.mapping = {}
+        self.debugging = True
+
+    def nextid(self):
+        self.next_id += 1
+        return self.next_id
+
+    def tohex(self, binhex):
+        return binascii.hexlify(binhex)
+
+    def mode(self, fctx):
+        flags = fctx.flags()
+
+        if 'l' in flags:
+          mode = '120000'
+        elif 'x' in flags:
+          mode = '100755'
+        else:
+          mode = '100644'
+
+        return mode
+
+    def parents(self, parents):
+        parents = [self.tohex(i.node()) for i in parents]
+        parents = [i for i in parents if i != self.nullref]
+        assert all(i in self.mapping for i in parents)
+        parents = [':%d' % self.mapping[i] for i in parents]
+
+        return parents
+
+    def ref(self, ctx):
+        return self.prefix + ctx.branch()
+
+    def write(self, *args):
+        msg = ''.join([str(i) for i in args])
+        sys.stdout.write(msg)
+
+    def debug(self, msg):
+        assert LF not in msg
+        self.write('#', SP, msg, LF)
+
+    def feature(self, feature, value=None):
+        if value:
+            self.write('feature', SP, feature, '=', value, LF)
+        else:
+            self.write('feature', SP, feature, LF)
+
+    def option(self, option, value=None):
+        if value:
+            self.write('option', SP, option, '=', value, LF)
+        else:
+            self.write('option', SP, option, LF)
+
+    def option_quiet(self):
+        self.option('quiet')
+
+    def feature_relative_marks(self):
+        self.feature('relative-marks')
+
+    def feature_export_marks(self, marks):
+        self.feature('export-marks', marks)
+
+    def feature_import_marks(self, marks):
+        self.feature('import-marks', marks)
+
+    def feature_force(self):
+        self.feature('force')
+
+    def progress(self, message):
+        self.write('progress', SP, message, LF)
+
+    def write_data(self, data):
+        count = len(data)
+        self.write('data', SP, count, LF)
+        self.write(data, LF)
+
+    def write_mark(self, idnum):
+        self.write('mark', SP, ':', idnum, LF)
+
+    def write_blob(self, data, idnum):
+        self.write('blob', LF)
+        self.write_mark(idnum)
+        self.write_data(data)
+
+    def write_file(self, ctx, file, idnum):
+        fctx = ctx.filectx(file)
+        data = fctx.data()
+
+        self.write_blob(data, idnum)
+
+    def write_commit(self, ref):
+        self.write('commit', SP, ref, LF)
+
+    def write_author(self, author):
+        self.write('author', SP, author, LF)
+
+    def write_committer(self, committer):
+        self.write('committer', SP, committer, LF)
+
+    def write_from(self, parent):
+        self.write('from', SP, parent, LF)
+
+    def write_merge(self, parent):
+        self.write('merge', SP, parent, LF)
+
+    def write_reset(self, ref, idnum):
+        self.write('reset', SP, ref, LF)
+        self.write('from', SP, ':', idnum, LF)
+
+    def write_parents(self, parents):
+        parents = self.parents(parents)
+
+        # first commit
+        if not parents:
+            return
+
+        parent = parents[0]
+
+        self.write_from(parent)
+
+        for parent in parents[1:]:
+            self.write_merge(parent)
+
+    def write_filedeleteall(self):
+        self.write('deleteall', LF)
+
+    def write_filedelete(self, ctx, name):
+        self.write('D', SP, name, LF)
+
+    def write_filemodify_mark(self, mode, name, mark):
+        self.write('M', SP, mode, SP, ':', mark, SP, name, LF)
+
+    def write_filemodify_inline(self, mode, name, data):
+        self.write('M', SP, mode, SP, 'inline', SP, name, LF)
+        self.write_data(data)
+
+    def write_filemodify(self, ctx, name):
+        fctx = ctx.filectx(name)
+        man = ctx.manifest()
+        nodesha = man[name]
+        hash = self.tohex(nodesha)
+        mode = self.mode(fctx)
+
+        if hash in self.mapping:
+            mark = self.mapping[hash]
+            self.write_filemodify_mark(mode, name, mark)
+        else:
+            data = fctx.data()
+            self.write_filemodify_inline(mode, name, data)
+
+    def write_files(self, ctx):
+        man = ctx.manifest()
+
+        if len(ctx.parents()) == 2:
+            self.write_filedeleteall()
+            for name in man:
+                self.write_filemodify(ctx, name)
+        else:
+            for name in ctx.files():
+                # file got deleted
+                if name not in man:
+                    self.write_filedelete(ctx, name)
+                else:
+                    self.write_filemodify(ctx, name)
+
+    def export_files(self, ctx):
+        man = ctx.manifest()
+
+        for name in [i for i in ctx.files() if i in man]:
+            idnum = self.nextid()
+            nodesha = man[name]
+            hash = self.tohex(nodesha)
+
+            self.write_file(ctx, name, idnum)
+            self.mapping[hash] = idnum
+
+    def export_commit(self, ctx, ref, idnum, msg, parents):
+        author = self.git_hg.get_author(ctx)
+        committer = self.git_hg.get_committer(ctx)
+        committer = committer if committer else author
+
+        self.debug('exporting commit')
+        self.write_commit(ref)
+        self.write_mark(idnum)
+        self.write_author(author)
+        self.write_committer(committer)
+        self.write_data(msg)
+        self.write_parents(parents)
+        self.write_files(ctx)
+        self.debug('commit exported')
+
+    def export_revision(self, ctx):
+        nodesha = ctx.node()
+        hash = self.tohex(nodesha)
+
+        if hash in self.mapping:
+            return False
+
+        self.export_files(ctx)
+
+        idnum = self.nextid()
+
+        ref = self.ref(ctx)
+        msg = self.git_hg.get_message(ctx)
+        parents = self.git_hg.get_parents(ctx)
+
+        self.export_commit(ctx, ref, idnum, msg, parents)
+        self.mapping[hash] = idnum
+
+        return True
+
+    def export_branch(self, name, rev):
+        ctx = self.repo.changectx(rev)
+        nodesha = ctx.node()
+        hash = self.tohex(nodesha)
+        idnum = self.mapping[hash]
+
+        ref = self.prefix + name
+
+        self.write_reset(ref, idnum)
+
+    def export_repo(self, refs):
+        self.option_quiet()
+        self.feature_force()
+
+        exported = printed = False
+
+        for rev in self.repo.changelog:
+            ctx = self.repo.changectx(rev)
+            exported = self.export_revision(ctx) or exported
+
+            if (exported and not printed) or (exported and rev%1000 == 0):
+                self.progress("Exported revision %d.\n" % rev)
+                printed = True
+
+    def write_marks(self, base):
+        dirname = self.repo.get_base_path(base)
+        path = os.path.join(dirname, 'hg.marks')
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+        f = open(path, 'w') #self.repo.opener(self.marksfile, 'w', atomictemp=True)
+
+        second = lambda (a, b): b
+
+        for hash, mark in sorted(self.mapping.iteritems(), key=second):
+            f.write(':%d %s\n' % (mark, hash))
+
+        f.close() #f.rename()
+
+    def read_marks(self, base):
+        dirname = self.repo.get_base_path(base)
+        path = os.path.join(dirname, 'hg.marks')
+
+        if not os.path.exists(path):
+            sys.stderr.write("warning: cannot find " + path)
+            return
+
+        f = open(path) #self.repo.opener(self.marksfile)
+
+        marks = [i.strip().split(' ') for i in f.readlines()]
+
+        self.mapping = dict((i[1], int(i[0][1:])) for i in marks)
+        self.next_id = max(self.mapping.values())
+

From 82b1c41b46efd38e442ffdbdc646628f6e94296c Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:38:43 +0200
Subject: [PATCH 3442/3720] git-remote-hg: add
 GitExporter/GitImporter/NonLocalGit

This is inftrastructure required to implement git-remote-hg.
---
 git_remote_helpers/hg/__init__.py  |  0
 git_remote_helpers/hg/exporter.py  | 29 +++++++++++++++++
 git_remote_helpers/hg/importer.py  | 29 +++++++++++++++++
 git_remote_helpers/hg/non_local.py | 51 ++++++++++++++++++++++++++++++
 git_remote_helpers/hg/util.py      | 14 ++++++++
 5 files changed, 123 insertions(+)
 create mode 100644 git_remote_helpers/hg/__init__.py
 create mode 100644 git_remote_helpers/hg/exporter.py
 create mode 100644 git_remote_helpers/hg/importer.py
 create mode 100644 git_remote_helpers/hg/non_local.py
 create mode 100644 git_remote_helpers/hg/util.py

diff --git a/git_remote_helpers/hg/__init__.py b/git_remote_helpers/hg/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/git_remote_helpers/hg/exporter.py b/git_remote_helpers/hg/exporter.py
new file mode 100644
index 0000000000..20b564dfc0
--- /dev/null
+++ b/git_remote_helpers/hg/exporter.py
@@ -0,0 +1,29 @@
+import binascii
+import os.path
+import sys
+
+from git_remote_helpers.hg import hgexport
+
+
+class GitExporter(object):
+    def __init__(self, repo):
+        self.repo = repo
+
+    def export_repo(self, base, refs):
+        gitmarksfile = os.path.join(self.repo.hash, 'git.marks')
+
+        exporter = hgexport.HgExportGenerator(self.repo)
+
+        exporter.feature_relative_marks()
+        exporter.feature_export_marks(gitmarksfile)
+
+        dirname = self.repo.get_base_path(base)
+        path = os.path.abspath(os.path.join(dirname, 'git.marks'))
+
+        if os.path.exists(path):
+            exporter.feature_import_marks(gitmarksfile)
+            exporter.read_marks(base)
+
+        exporter.export_repo(refs)
+
+        exporter.write_marks(base)
diff --git a/git_remote_helpers/hg/importer.py b/git_remote_helpers/hg/importer.py
new file mode 100644
index 0000000000..ff1eabda02
--- /dev/null
+++ b/git_remote_helpers/hg/importer.py
@@ -0,0 +1,29 @@
+import os.path
+import sys
+
+from git_remote_helpers.hg import hgimport
+from git_remote_helpers.fastimport import processor, parser
+
+
+class GitImporter(object):
+    def __init__(self, repo):
+        self.repo = repo
+
+    def do_import(self, base):
+        sources = ["-"]
+
+        dirname = self.repo.get_base_path(base)
+
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+
+        procc = hgimport.HgImportProcessor(self.repo.ui, self.repo)
+
+        marks_file = os.path.abspath(os.path.join(dirname, 'hg.marks'))
+
+        if os.path.exists(marks_file):
+            procc.load_marksfile(marks_file)
+
+        processor.parseMany(sources, parser.ImportParser, procc)
+
+        procc.write_marksfile(marks_file)
diff --git a/git_remote_helpers/hg/non_local.py b/git_remote_helpers/hg/non_local.py
new file mode 100644
index 0000000000..715bd68cd4
--- /dev/null
+++ b/git_remote_helpers/hg/non_local.py
@@ -0,0 +1,51 @@
+import os
+
+from git_remote_helpers.util import die, warn
+
+class NonLocalHg(object):
+    def __init__(self, repo):
+        self.repo = repo
+        self.hg = repo.hg
+
+    def clone(self, base):
+        path = self.repo.get_base_path(base)
+
+        # already cloned
+        if os.path.exists(os.path.join(path, '.hg')):
+            return path
+
+        if not os.path.exists(path):
+            os.makedirs(path)
+
+        if self.repo.path.endswith(".hg"):
+            from_path = self.repo.path[:-3]
+        else:
+            from_path = self.repo.path
+
+        self.repo.ui.setconfig('ui', 'quiet', "true")
+        self.hg.clone(self.repo.ui, from_path, path, update=False, pull=True)
+
+        return path
+
+    def update(self, base):
+        path = self.repo.get_base_path(base)
+
+        if not os.path.exists(path):
+            die("could not find repo at %s", path)
+
+        repo = self.hg.repository(self.repo.ui, path)
+
+        repo.ui.setconfig('ui', 'quiet', "true")
+        repo.pull(self.repo, heads=self.repo.heads(), force=True)
+
+    def push(self, base):
+        path = self.repo.get_base_path(base)
+
+        if not os.path.exists(path):
+            die("could not find repo at %s", path)
+
+        repo = self.hg.repository(self.repo.ui, path)
+
+        self.repo.ui.setconfig('ui', 'quiet', "true")
+        repo.ui.setconfig('ui', 'quiet', "true")
+        repo.push(self.repo, force=False)
diff --git a/git_remote_helpers/hg/util.py b/git_remote_helpers/hg/util.py
new file mode 100644
index 0000000000..2cd54c1ad0
--- /dev/null
+++ b/git_remote_helpers/hg/util.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+from mercurial import hg
+
+def parseurl(url, heads=[]):
+    url, heads = hg.parseurl(url, heads)
+    if isinstance(heads, tuple) and len(heads) == 2:
+        # hg 1.6 or later
+        _junk, heads = heads
+    if heads:
+        checkout = heads[0]
+    else:
+        checkout = None
+    return url, heads, checkout

From a5cc7703e786879bec7106375e3e32eea0ad7a13 Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Fri, 16 Mar 2012 15:54:33 +0100
Subject: [PATCH 3443/3720] remote-hg: adjust to hg 1.9

hg 1.0 changed the signature of hg.clone(). Adjust to it.

A real fix would need to check the hg version or try/catch.
---
 git_remote_helpers/hg/non_local.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/non_local.py b/git_remote_helpers/hg/non_local.py
index 715bd68cd4..abb7908da0 100644
--- a/git_remote_helpers/hg/non_local.py
+++ b/git_remote_helpers/hg/non_local.py
@@ -23,7 +23,7 @@ class NonLocalHg(object):
             from_path = self.repo.path
 
         self.repo.ui.setconfig('ui', 'quiet', "true")
-        self.hg.clone(self.repo.ui, from_path, path, update=False, pull=True)
+        self.hg.clone(self.repo.ui, {}, from_path, path, update=False, pull=True)
 
         return path
 

From 2ec3a3e9459c8ff21fc76ad6939e03bc37eaea0d Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:38:57 +0200
Subject: [PATCH 3444/3720] git-remote-hg: add the helper

The helper uses the previously added infrastructure.
---
 .gitignore                  |   1 +
 Makefile                    |   1 +
 git-remote-hg.py            | 101 ++++++++++++++++++++++++++++++++++++
 git_remote_helpers/setup.py |   2 +-
 4 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 git-remote-hg.py

diff --git a/.gitignore b/.gitignore
index 87fcc5f6ff..cc14de131d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -119,6 +119,7 @@
 /git-remote-fd
 /git-remote-ext
 /git-remote-testgit
+/git-remote-hg
 /git-repack
 /git-replace
 /git-repo-config
diff --git a/Makefile b/Makefile
index 77111b1f46..2626216f9e 100644
--- a/Makefile
+++ b/Makefile
@@ -443,6 +443,7 @@ SCRIPT_PERL += git-send-email.perl
 SCRIPT_PERL += git-svn.perl
 
 SCRIPT_PYTHON += git-remote-testgit.py
+SCRIPT_PYTHON += git-remote-hg.py
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
 	  $(patsubst %.perl,%,$(SCRIPT_PERL)) \
diff --git a/git-remote-hg.py b/git-remote-hg.py
new file mode 100644
index 0000000000..fdf61a737d
--- /dev/null
+++ b/git-remote-hg.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+import sys
+import os
+sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
+
+from git_remote_helpers.helper import RemoteHelper
+from git_remote_helpers.util import debug, die, warn
+from git_remote_helpers.hg import util
+from git_remote_helpers.hg.hg import GitHg
+from git_remote_helpers.hg.exporter import GitExporter
+from git_remote_helpers.hg.importer import GitImporter
+from git_remote_helpers.hg.non_local import NonLocalHg
+
+
+class HgRemoteHelper(RemoteHelper):
+    def get_repo(self, alias, url):
+        """Returns a hg.repository object initialized for usage.
+        """
+
+        try:
+            from mercurial import hg, ui
+        except ImportError:
+            die("Mercurial python libraries not installed")
+
+        remote = False
+
+        if url.startswith("remote://"):
+            remote = True
+            url = "file://%s" % url[9:]
+
+        ui = ui.ui()
+        source, revs, checkout = util.parseurl(ui.expandpath(url), ['default'])
+        repo = hg.repository(ui, source)
+        if repo.capable('branchmap'):
+            revs += repo.branchmap().keys()
+            revs = set(revs)
+
+        prefix = 'refs/hg/%s/' % alias
+        debug("prefix: '%s'", prefix)
+
+        repo.marksfile = 'git.marks'
+        repo.hg = hg
+        repo.prefix = prefix
+        repo.revs = revs
+
+        self.setup_repo(repo, alias)
+
+        repo.git_hg = GitHg(warn)
+        repo.exporter = GitExporter(repo)
+        repo.importer = GitImporter(repo)
+        repo.non_local = NonLocalHg(repo)
+
+        repo.is_local = not remote and repo.local()
+
+        return repo
+
+    def local_repo(self, repo, path):
+        """Returns a hg.repository object initalized for usage.
+        """
+
+        local = repo.hg.repository(repo.ui, path)
+
+        self.setup_local_repo(local, repo)
+
+        local.git_hg = repo.git_hg
+        local.hg = repo.hg
+        local.revs = repo.revs
+        local.exporter = GitExporter(local)
+        local.importer = GitImporter(local)
+        local.is_local = repo.is_local
+
+        return local
+
+    def do_list(self, repo, args):
+        """Lists all known references.
+        """
+
+        for ref in repo.revs:
+            debug("? refs/heads/%s", ref)
+            print "? refs/heads/%s" % ref
+
+        debug("@refs/heads/default HEAD")
+        print "@refs/heads/default HEAD"
+
+        print # end list
+
+    def sanitize(self, value):
+        """Cleans up the url.
+        """
+
+        if value.startswith('hg::'):
+            value = value[4:]
+
+        return value
+
+    def get_refs(self, repo, gitdir):
+        return repo.branchmap()
+
+if __name__ == '__main__':
+    sys.exit(HgRemoteHelper().main(sys.argv))
diff --git a/git_remote_helpers/setup.py b/git_remote_helpers/setup.py
index a19c061fdf..4799513c24 100644
--- a/git_remote_helpers/setup.py
+++ b/git_remote_helpers/setup.py
@@ -14,5 +14,5 @@ setup(
     url = 'http://www.git-scm.com/',
     package_dir = {'git_remote_helpers': ''},
     packages = ['git_remote_helpers', 'git_remote_helpers.git',
-                'git_remote_helpers.fastimport'],
+                'git_remote_helpers.fastimport', 'git_remote_helpers.hg'],
 )

From 31470d459ce8c38a6f0022184db1b46464fad04f Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:39:03 +0200
Subject: [PATCH 3445/3720] git-remote-hg: add tests

---
 t/t5801-remote-hg.sh | 137 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 137 insertions(+)
 create mode 100755 t/t5801-remote-hg.sh

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
new file mode 100755
index 0000000000..18915ddb8c
--- /dev/null
+++ b/t/t5801-remote-hg.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Sverre Rabbelier
+#
+
+test_description='Test remote-helper import and export commands'
+
+. ./test-lib.sh
+
+if test_have_prereq PYTHON && "$PYTHON_PATH" -c '
+import sys
+if sys.hexversion < 0x02040000:
+    sys.exit(1)
+'
+then
+	:
+else
+	skip_all='skipping git remote-hg tests: requires Python 2.4 or newer'
+	test_done
+fi
+
+# Call cmp with the arguments -x ".hg" -x ".git"  
+
+vcs_cmp () {
+	$DIFF -u -x ".hg" -x ".git" $1 $2
+}
+
+ROOT=$PWD
+
+test_expect_success 'setup repository' '
+	printf "[ui]\nusername = A U Thor " > \
+		${HOME}/.hgrc &&
+	mkdir server &&
+	hg init server/.hg &&
+	hg clone "$ROOT/server" public &&
+	(cd public &&
+	 echo content >file &&
+	 hg add file &&
+	 hg commit -m one &&
+	 hg push)
+'
+
+test_expect_success 'cloning from local repo' '
+	git clone "hg::file://${ROOT}/server" localclone &&
+	vcs_cmp public localclone
+'
+
+test_expect_success 'cloning from remote repo' '
+	git clone "hg::remote://${ROOT}/server" clone &&
+	vcs_cmp public clone
+'
+
+test_expect_success 'create new commit on remote' '
+	(cd public &&
+	 echo content >>file &&
+	 hg commit -A -m two &&
+	 hg push)
+'
+
+test_expect_success 'pulling from local repo' '
+	(cd localclone && git pull) &&
+	vcs_cmp public localclone
+'
+
+test_expect_success 'pulling from remote remote' '
+	(cd clone && git pull) &&
+	vcs_cmp public clone
+'
+
+test_expect_success 'pushing to local empty repo' '
+	hg init localempty &&
+	(cd localclone &&
+	git push --all "hg::file://${ROOT}/localempty") &&
+	(cd localempty &&
+	hg up tip) &&
+	vcs_cmp localclone localempty
+'
+
+test_expect_success 'pushing to remote empty repo' '
+	hg init empty &&
+	(cd localclone &&
+	git push --all "hg::remote://${ROOT}/empty") &&
+	(cd empty &&
+	hg up tip) &&
+	vcs_cmp localclone empty
+'
+
+test_expect_success 'pushing to local repo' '
+	(cd localclone &&
+	echo content >>file &&
+	git commit -a -m three &&
+	git push) &&
+	(cd server &&
+	hg up tip) &&
+	vcs_cmp localclone server
+'
+
+test_expect_success 'synch with changes from localclone' '
+	(cd clone &&
+	 git pull)
+'
+
+test_expect_success 'pushing remote local repo' '
+	(cd clone &&
+	echo content >>file &&
+	git commit -a -m four &&
+	git push) &&
+	(cd server &&
+	hg up tip) &&
+	vcs_cmp clone server
+'
+
+test_expect_success 'creating new branch' '
+	(cd public &&
+	hg branch different-branch &&
+	echo different >> file &&
+	hg commit -m five &&
+	hg push -f)
+'
+
+test_expect_success 'pull in new branch to local repository' '
+	(cd localclone &&
+	git fetch origin default &&
+	test_must_fail git rev-parse -q --verify refs/remotes/origin/different-branch &&
+	git fetch &&
+	git rev-parse --no-revs --verify refs/remotes/origin/different-branch)
+'
+
+test_expect_success 'pull in new branch to remote repository' '
+	(cd clone &&
+	git fetch origin default &&
+	test_must_fail git rev-parse -q --verify refs/remotes/origin/different-branch &&
+	git fetch &&
+	git rev-parse --no-revs --verify refs/remotes/origin/different-branch)
+'
+
+test_done

From 1d49c1b17447fd522427169c658fec5489a69c58 Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Sat, 3 Mar 2012 19:53:38 +0100
Subject: [PATCH 3446/3720] t5800: clarify skip message

The skip message takes about remote-hg while the tests are about the
general remote helper framework (and don't require hg). Correct the
message.
---
 t/t5800-remote-helpers.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 0be4c7ef79..28e929a501 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -8,7 +8,7 @@ test_description='Test remote-helper import and export commands'
 . ./test-lib.sh
 
 if ! test_have_prereq PYTHON ; then
-	skip_all='skipping git-remote-hg tests, python not available'
+	skip_all='skipping remote helper tests, python not available'
 	test_done
 fi
 
@@ -17,7 +17,7 @@ import sys
 if sys.hexversion < 0x02040000:
     sys.exit(1)
 ' || {
-	skip_all='skipping git-remote-hg tests, python version < 2.4'
+	skip_all='skipping remote helper tests, python version < 2.4'
 	test_done
 }
 

From d0a618b421cb1df449ff27de22a7de25b728ecc7 Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Sat, 3 Mar 2012 19:57:22 +0100
Subject: [PATCH 3447/3720] t5801: skip without hg

The tests for remote-hg require hg, so skip them all when there is no
hg available.
---
 t/t5801-remote-hg.sh | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
index 18915ddb8c..2e68372d59 100755
--- a/t/t5801-remote-hg.sh
+++ b/t/t5801-remote-hg.sh
@@ -19,6 +19,12 @@ else
 	test_done
 fi
 
+if ! type hg >/dev/null 2>&1
+then
+	skip_all='skipping git remote-hg tests: requires hg'
+	test_done
+fi
+
 # Call cmp with the arguments -x ".hg" -x ".git"  
 
 vcs_cmp () {

From 5a0ff88aba8ae851261dd8766653fcfef57b2d82 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 29 Mar 2012 13:38:43 -0500
Subject: [PATCH 3448/3720] remote-hg: Postel's law dictates we should handle
 Author

We should handle a missing space before the email part of an author ident
gracefully. See for example the icedtea6 repository.

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index 758ba242d8..dd5756d4bb 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -76,7 +76,7 @@ class GitHg(object):
         author = ctx.user()
 
         # check for git author pattern compliance
-        regex = re.compile('^(.*?) \<(.*?)\>(.*)$')
+        regex = re.compile('^(.*?) ?\<(.*?)\>(.*)$')
         a = regex.match(author)
 
         if a:

From 649a45202b366206322fa0185df81b9b1903314c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 00:27:45 -0500
Subject: [PATCH 3449/3720] remote-hg: another case of Postel's law

This change allows invalid input from Mercurial repositories where the
author is recorded as 'Name ').

With this change, importing http://scelenic.com/hg itself no longer fails
with:

	fatal: Missing > in ident string: Benoit Boissinot
	 1129685868 -0700

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index dd5756d4bb..cdd13fa513 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -76,17 +76,21 @@ class GitHg(object):
         author = ctx.user()
 
         # check for git author pattern compliance
-        regex = re.compile('^(.*?) ?\<(.*?)\>(.*)$')
+        regex = re.compile('^(.*?) ?\<(.*?)(|\>(.*))$')
         a = regex.match(author)
 
         if a:
             name = a.group(1)
             email = a.group(2)
-            if len(a.group(3)) > 0:
-                name += ' ext:(' + urllib.quote(a.group(3)) + ')'
+            extra = a.group(4)
+            if not extra is None and len(extra) > 0:
+                name += ' ext:(' + urllib.quote(extra) + ')'
             author = name + ' <' + email + '>'
         else:
-            author = author + ' '
+            if author.find('<') >= 0:
+                author = author + '>'
+            else:
+                author = author + ' '
 
         if 'author' in ctx.extra():
             author = apply_delta(author, ctx.extra()['author'])

From dfcd9fdf22fa193f31f8a5f74e848cfd97301f75 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 00:56:31 -0500
Subject: [PATCH 3450/3720] remote-hg: handle another funny author line from
 http://scelenic.com/hg

In this case: David Soria Parra  php.net>.

With this last of three Postel patches, remote-hg can import the
Mercurial repository completely.

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index cdd13fa513..d835ed47e4 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -84,7 +84,13 @@ class GitHg(object):
             email = a.group(2)
             extra = a.group(4)
             if not extra is None and len(extra) > 0:
-                name += ' ext:(' + urllib.quote(extra) + ')'
+                if email.endswith('  ', '.')
+                    extra = extra.replace('>', '')
+                    email = email[:-4] + '@' + extra
+                else:
+                    name += ' ext:(' + urllib.quote(extra) + ')'
             author = name + ' <' + email + '>'
         else:
             if author.find('<') >= 0:

From 699dee3664e07c8f8b7487e215cba394448a82fe Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 01:01:21 -0500
Subject: [PATCH 3451/3720] Mark all remote-hg push tests as broken

For now, remote-hg cannot be used for pushing. The respective tests fail
thusly:

warning: non-alnum alias 'remote:///git/t/trash directory.t5801-remote-hg/empty'
transaction abort!
rollback completed
Traceback (most recent call last):
  File "/git/git-remote-hg", line 101, in 
    sys.exit(HgRemoteHelper().main(sys.argv))
  File ".../lib/git_remote_helpers/helper.py", line 197, in main
    more = self.read_one_line(repo)
  File ".../lib/git_remote_helpers/helper.py", line 163, in read_one_line
    func(repo, cmdline)
  File ".../lib/git_remote_helpers/helper.py", line 121, in do_export
    localrepo.importer.do_import(localrepo.gitdir)
  File ".../lib/git_remote_helpers/hg/importer.py", line 27, in do_import
    processor.parseMany(sources, parser.ImportParser, procc)
  File ".../lib/git_remote_helpers/fastimport/processor.py", line 219,
        in parseMany
    processor.process(parser.parse())
  File ".../lib/git_remote_helpers/fastimport/processor.py", line 76,
        in process
    handler(self, cmd)
  File ".../lib/git_remote_helpers/hg/hgimport.py", line 262,
        in commit_handler
    self.idmap[cmd.id] = self.putcommit(modified, modes, copies, cmt)
  File ".../lib/git_remote_helpers/hg/hgimport.py", line 294, in putcommit
    self.repo.commitctx(ctx)
  File "/lib/python/mercurial/localrepo.py", line 1315, in commitctx
    phases.retractboundary(self, targetphase, [n])
  File "/lib/python/mercurial/phases.py", line 201, in retractboundary
    currentroots.intersection_update(ctx.node() for ctx in ctxs)
  File "/lib/python/mercurial/phases.py", line 201, in 
    currentroots.intersection_update(ctx.node() for ctx in ctxs)
  File "/lib/python/mercurial/localrepo.py", line 264, in set
    for r in self.revs(expr, *args):
TypeError: 'set' object is not callable

Signed-off-by: Johannes Schindelin 
---
 t/t5801-remote-hg.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
index 2e68372d59..e0e60e8009 100755
--- a/t/t5801-remote-hg.sh
+++ b/t/t5801-remote-hg.sh
@@ -73,7 +73,7 @@ test_expect_success 'pulling from remote remote' '
 	vcs_cmp public clone
 '
 
-test_expect_success 'pushing to local empty repo' '
+test_expect_failure 'pushing to local empty repo' '
 	hg init localempty &&
 	(cd localclone &&
 	git push --all "hg::file://${ROOT}/localempty") &&
@@ -82,7 +82,7 @@ test_expect_success 'pushing to local empty repo' '
 	vcs_cmp localclone localempty
 '
 
-test_expect_success 'pushing to remote empty repo' '
+test_expect_failure 'pushing to remote empty repo' '
 	hg init empty &&
 	(cd localclone &&
 	git push --all "hg::remote://${ROOT}/empty") &&
@@ -91,7 +91,7 @@ test_expect_success 'pushing to remote empty repo' '
 	vcs_cmp localclone empty
 '
 
-test_expect_success 'pushing to local repo' '
+test_expect_failure 'pushing to local repo' '
 	(cd localclone &&
 	echo content >>file &&
 	git commit -a -m three &&
@@ -106,7 +106,7 @@ test_expect_success 'synch with changes from localclone' '
 	 git pull)
 '
 
-test_expect_success 'pushing remote local repo' '
+test_expect_failure 'pushing remote local repo' '
 	(cd clone &&
 	echo content >>file &&
 	git commit -a -m four &&

From 8b89e59b7356c6bcfcc111b73f479a5321a283d5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 02:12:53 -0500
Subject: [PATCH 3452/3720] remote-hg: do not interfer with hg's revs() method

Matt Mackall introduced a revs() method to the localrepo class on Wed
Nov 2 13:37:34 2011 in the commit 'localrepo: add revs helper method'.
It is used when constructing a commit in memory.

If we store the set of revs we want to handle under the same name, it
overrides that method, resulting in an unpleasant 'TypeError: 'set'
object is not callable' whenever we want to push (as we are constructing
commits in memory, then).

So let's work around that by renaming our field to 'revs2' and hope that
upstream Mercurial does not introduce a field of that name, too.

Signed-off-by: Johannes Schindelin 
---
 git-remote-hg.py               | 6 +++---
 git_remote_helpers/git/repo.py | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/git-remote-hg.py b/git-remote-hg.py
index fdf61a737d..1ee57f4009 100644
--- a/git-remote-hg.py
+++ b/git-remote-hg.py
@@ -42,7 +42,7 @@ class HgRemoteHelper(RemoteHelper):
         repo.marksfile = 'git.marks'
         repo.hg = hg
         repo.prefix = prefix
-        repo.revs = revs
+        repo.revs2 = revs # must not override repo.revs()
 
         self.setup_repo(repo, alias)
 
@@ -65,7 +65,7 @@ class HgRemoteHelper(RemoteHelper):
 
         local.git_hg = repo.git_hg
         local.hg = repo.hg
-        local.revs = repo.revs
+        local.revs2 = repo.revs2
         local.exporter = GitExporter(local)
         local.importer = GitImporter(local)
         local.is_local = repo.is_local
@@ -76,7 +76,7 @@ class HgRemoteHelper(RemoteHelper):
         """Lists all known references.
         """
 
-        for ref in repo.revs:
+        for ref in repo.revs2:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
index 4536233868..2bf6a729a4 100644
--- a/git_remote_helpers/git/repo.py
+++ b/git_remote_helpers/git/repo.py
@@ -61,7 +61,7 @@ class GitRepo(object):
         self.revmap = dict(sanitize(i) for i in output)
         if "HEAD" in self.revmap:
             del self.revmap["HEAD"]
-        self.revs = self.revmap.keys()
+        self.revs2 = self.revmap.keys()
         ofile.close()
 
     def get_head(self):

From 1729079df8824b5ee6af0eaa2874594821c1ab77 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 02:18:24 -0500
Subject: [PATCH 3453/3720] fixup! Mark all remote-hg push tests as broken

This reverts that. With the next rebasing merge, just 'git rebase
--continue'.
---
 t/t5801-remote-hg.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
index e0e60e8009..2e68372d59 100755
--- a/t/t5801-remote-hg.sh
+++ b/t/t5801-remote-hg.sh
@@ -73,7 +73,7 @@ test_expect_success 'pulling from remote remote' '
 	vcs_cmp public clone
 '
 
-test_expect_failure 'pushing to local empty repo' '
+test_expect_success 'pushing to local empty repo' '
 	hg init localempty &&
 	(cd localclone &&
 	git push --all "hg::file://${ROOT}/localempty") &&
@@ -82,7 +82,7 @@ test_expect_failure 'pushing to local empty repo' '
 	vcs_cmp localclone localempty
 '
 
-test_expect_failure 'pushing to remote empty repo' '
+test_expect_success 'pushing to remote empty repo' '
 	hg init empty &&
 	(cd localclone &&
 	git push --all "hg::remote://${ROOT}/empty") &&
@@ -91,7 +91,7 @@ test_expect_failure 'pushing to remote empty repo' '
 	vcs_cmp localclone empty
 '
 
-test_expect_failure 'pushing to local repo' '
+test_expect_success 'pushing to local repo' '
 	(cd localclone &&
 	echo content >>file &&
 	git commit -a -m three &&
@@ -106,7 +106,7 @@ test_expect_success 'synch with changes from localclone' '
 	 git pull)
 '
 
-test_expect_failure 'pushing remote local repo' '
+test_expect_success 'pushing remote local repo' '
 	(cd clone &&
 	echo content >>file &&
 	git commit -a -m four &&

From 64a8a034d2bab8fa468a86ffd4dc46e8c3609452 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 22 Mar 2012 19:17:03 +0100
Subject: [PATCH 3454/3720] Windows: Always normalize paths to Windows-style

It appears that `pwd` returns the POSIX-style or the DOS-style path
depending which style the previous `cd` used. To normalize, enforce `pwd
-W` in scripts.

From the original e-mail exchange:

On Thu, Mar 22, 2012 at 11:13:37AM +0100, Sebastian Schuberth wrote:
> On Wed, Mar 21, 2012 at 22:21, Johannes Sixt  wrote:
>
> > I build git and run its tests outside the msysgit environment. Does that
> > explain the difference? (And I use CMD.)
>
> It does not make a difference for me. I started cmd.exe at
> c:\msysgit\git\t, added c:\msysgit\bin temporarily to PATH, and ran
> "sh t5526-fetch-submodules.sh -i -v", and the test still fails.

Yes it probably does. Johannes said that he runs the tests outside of
the msysgit folder. That way there is only one path the submodule script
gets reported and not two like '/c/msysgit/git' and '/git'.

That would explain to me why it is passing.

I am afraid that the only solution is to patch msys itself to report the
long absolute path when passing window style paths to cd. Currently when
I do

	cd c:/msysgit/git

I will end up in '/git' instead of the long path.

I found that there is a -W option to pwd in msys bash which makes it
always return the real windows path. A normalization in that direction
is unique and thus might be more robust. Have a look at the attached
patch. With this at least t5526 passes. I was not able to run the whole
testsuite properly at the moment. I can have a look at that tomorrow.

What do you think?

Cheers Heiko

Signed-off-by: Johannes Schindelin 
---
 git-sh-setup.sh  | 2 ++
 git-submodule.sh | 3 ---
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index d9fc4be050..b6c55e6dde 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -250,6 +250,8 @@ case $(uname -s) in
 	find () {
 		/usr/bin/find "$@"
 	}
+	# Let pwd always return the uniqe real windows path
+	alias pwd='pwd -W'
 	is_absolute_path () {
 		case "$1" in
 		[/\\]* | [A-Za-z]:*)
diff --git a/git-submodule.sh b/git-submodule.sh
index efb0cfdfe9..08bc48aa50 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -151,9 +151,6 @@ module_clone()
 
 	a=$(cd "$gitdir" && pwd)/
 	b=$(cd "$path" && pwd)/
-	# normalize Windows-style absolute paths to POSIX-style absolute paths
-	case $a in [a-zA-Z]:/*) a=/${a%%:*}${a#*:} ;; esac
-	case $b in [a-zA-Z]:/*) b=/${b%%:*}${b#*:} ;; esac
 	# Remove all common leading directories after a sanity check
 	if test "${a#$b}" != "$a" || test "${b#$a}" != "$b"; then
 		die "$(eval_gettext "Gitdir '\$a' is part of the submodule path '\$b' or vice versa")"

From 6a78c1cc84215c9f6c1cfa22dc3e8b44cc328a5b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 13:04:35 -0500
Subject: [PATCH 3455/3720] Always auto-gc after calling a fast-import
 transport

After importing anything with fast-import, we should always let the
garbage collector do its job, since the objects are written to disk
inefficiently.

This brings down an initial import of http://selenic.com/hg from about
230 megabytes to about 14.

In the future, we may want to make this configurable on a per-remote
basis, or maybe teach fast-import about it in the first place.

Signed-off-by: Johannes Schindelin 
---
 transport-helper.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index f157b627d0..8c61fdcedc 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -12,6 +12,8 @@
 #include "sigchain.h"
 
 static int debug;
+/* TODO: put somewhere sensible, e.g. git_transport_options? */
+static int auto_gc = 1;
 
 struct helper_data {
 	const char *name;
@@ -476,6 +478,12 @@ static int fetch_with_import(struct transport *transport,
 		}
 	}
 	strbuf_release(&buf);
+	if (auto_gc) {
+		const char *argv_gc_auto[] = {
+			"gc", "--auto", "--quiet", NULL,
+		};
+		run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+	}
 	return 0;
 }
 

From de09888e88c72536cb75807f77da9555f39569e9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 14:47:14 -0500
Subject: [PATCH 3456/3720] fixup! remote-hg: do not interfer with hg's revs()
 method

---
 git-remote-testgit.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index d57c1dc393..f88a795951 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -56,7 +56,7 @@ class TestgitRemoteHelper(RemoteHelper):
         head is at clone time.
         """
 
-        for ref in repo.revs:
+        for ref in repo.revs2:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 

From 3c85385aaa88695f846de9b869633a5552e99a17 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 15:44:14 -0500
Subject: [PATCH 3457/3720] squash! remote-hg: do not interfer with hg's revs()
 method

FIXUP: the field is called 'revs_' now, Sverre likes that better.
---
 git-remote-hg.py               | 6 +++---
 git-remote-testgit.py          | 2 +-
 git_remote_helpers/git/repo.py | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/git-remote-hg.py b/git-remote-hg.py
index 1ee57f4009..4b619e9c4c 100644
--- a/git-remote-hg.py
+++ b/git-remote-hg.py
@@ -42,7 +42,7 @@ class HgRemoteHelper(RemoteHelper):
         repo.marksfile = 'git.marks'
         repo.hg = hg
         repo.prefix = prefix
-        repo.revs2 = revs # must not override repo.revs()
+        repo.revs_ = revs # must not override repo.revs()
 
         self.setup_repo(repo, alias)
 
@@ -65,7 +65,7 @@ class HgRemoteHelper(RemoteHelper):
 
         local.git_hg = repo.git_hg
         local.hg = repo.hg
-        local.revs2 = repo.revs2
+        local.revs_ = repo.revs_
         local.exporter = GitExporter(local)
         local.importer = GitImporter(local)
         local.is_local = repo.is_local
@@ -76,7 +76,7 @@ class HgRemoteHelper(RemoteHelper):
         """Lists all known references.
         """
 
-        for ref in repo.revs2:
+        for ref in repo.revs_:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 
diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index f88a795951..740e02b1f3 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -56,7 +56,7 @@ class TestgitRemoteHelper(RemoteHelper):
         head is at clone time.
         """
 
-        for ref in repo.revs2:
+        for ref in repo.revs_:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
index 2bf6a729a4..fa68e47101 100644
--- a/git_remote_helpers/git/repo.py
+++ b/git_remote_helpers/git/repo.py
@@ -61,7 +61,7 @@ class GitRepo(object):
         self.revmap = dict(sanitize(i) for i in output)
         if "HEAD" in self.revmap:
             del self.revmap["HEAD"]
-        self.revs2 = self.revmap.keys()
+        self.revs_ = self.revmap.keys()
         ofile.close()
 
     def get_head(self):

From 77f5ee0d66b9053061458f6e4cdc148decfd4b0c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 16:37:57 -0500
Subject: [PATCH 3458/3720] fast-export: report SHA-1 instead of gibberish when
 marks exist already

Cc: Pieter de Bie 
Signed-off-by: Johannes Schindelin 
---
 builtin/fast-export.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 137792d49d..1213155acf 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -644,7 +644,7 @@ static void import_marks(char *input_file)
 			die ("Could not read blob %s", sha1_to_hex(sha1));
 
 		if (object->flags & SHOWN)
-			error("Object %s already has a mark", sha1);
+			error("Object %s already has a mark", sha1_to_hex(sha1));
 
 		mark_object(object, mark);
 		if (last_idnum < mark)

From d084f44fb6039f2e36fed41b30a9f6bd6a1581f4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 21:09:49 -0500
Subject: [PATCH 3459/3720] Windows: make sure that merge-octopus only outputs
 LF line endings

This happens to shut up t7602 on Windows which would otherwise take
the different line endings for a sign that the merge failed.

Signed-off-by: Johannes Schindelin 
---
 git-merge-octopus.sh | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh
index 8643f74cb0..2226eeba99 100755
--- a/git-merge-octopus.sh
+++ b/git-merge-octopus.sh
@@ -71,7 +71,9 @@ do
 
 	case "$LF$common$LF" in
 	*"$LF$SHA1$LF"*)
-		echo "Already up-to-date with $pretty_name"
+		cat << EOF
+Already up-to-date with $pretty_name
+EOF
 		continue
 		;;
 	esac
@@ -83,7 +85,9 @@ do
 		# tree as the intermediate result of the merge.
 		# We still need to count this as part of the parent set.
 
-		echo "Fast-forwarding to: $pretty_name"
+		cat << EOF
+Fast-forwarding to: $pretty_name
+EOF
 		git read-tree -u -m $head $SHA1 || exit
 		MRC=$SHA1 MRT=$(git write-tree)
 		continue
@@ -91,7 +95,9 @@ do
 
 	NON_FF_MERGE=1
 
-	echo "Trying simple merge with $pretty_name"
+	cat << EOF
+Trying simple merge with $pretty_name
+EOF
 	git read-tree -u -m --aggressive  $common $MRT $SHA1 || exit 2
 	next=$(git write-tree 2>/dev/null)
 	if test $? -ne 0

From 2af037bc0b48a78443b92a6caaa9ad59b5cfddad Mon Sep 17 00:00:00 2001
From: Jeff King 
Date: Tue, 1 May 2012 04:41:42 -0400
Subject: [PATCH 3460/3720] send-pack: show progress when isatty(2)

The send_pack_args struct has two verbosity flags: "quiet"
and "progress". Originally, if "quiet" was set, we would
tell pack-objects explicitly to be quiet, and if "progress"
was set, we would tell it to show progress. Otherwise, we
told it neither, and it relied on isatty(2) to make the
decision itself.

However, commit 01fdc21 changed the meaning of these
variables. Now both "quiet" and "!progress" instruct us to
tell pack-objects to be quiet (and a non-zero "progress"
means the same as before). This works well for transports
which call send_pack directly, as the transport code copies
transport->progress into send_pack_args->progress, and they
both have the same meaning.

However, the code path of calling "git send-pack" was left
behind. It always sets "progress" to 0, and thus always
tells pack-objects to be quiet.  We can work around this by
checking isatty(2) ourselves in the cmd_send_pack code path,
restoring the original behavior of the send-pack command.

Signed-off-by: Jeff King 
Signed-off-by: Johannes Schindelin 
---
 builtin/send-pack.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 9df341c793..7d22715630 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -492,6 +492,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	if (!args.quiet)
+		args.progress = isatty(2);
+
 	if (args.stateless_rpc) {
 		conn = NULL;
 		fd[0] = 0;

From 89e203b06e1d7cb30752c5ca109f61f946ea8657 Mon Sep 17 00:00:00 2001
From: Jeff King 
Date: Tue, 1 May 2012 04:42:24 -0400
Subject: [PATCH 3461/3720] teach send-pack about --[no-]progress

The send_pack function gets a "progress" flag saying "yes,
definitely show progress" or "no, definitely do not show
progress". This gets set properly by transport_push when
send_pack is called directly.

However, when the send-pack command is executed separately
(as it is for the remote-curl helper), there is no way to
tell it "definitely do this". As a result, we do not
properly respect "git push --no-progress" for smart-http
remotes; you will still get progress if stderr is a tty.

This patch teaches send-pack --progress and --no-progress,
and teaches remote-curl to pass the appropriate option to
override send-pack's isatty check. This fixes the
--no-progress case above, and as a bonus, also makes "git
push --progress" work when stderr is not a tty.

Signed-off-by: Jeff King 
Signed-off-by: Johannes Schindelin 
---
 builtin/send-pack.c | 14 ++++++++++++--
 remote-curl.c       |  1 +
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 7d22715630..d5d7105ba2 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -410,6 +410,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 	const char *receivepack = "git-receive-pack";
 	int flags;
 	int nonfastforward = 0;
+	int progress = -1;
 
 	argv++;
 	for (i = 1; i < argc; i++, argv++) {
@@ -452,6 +453,14 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 				args.verbose = 1;
 				continue;
 			}
+			if (!strcmp(arg, "--progress")) {
+				progress = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--no-progress")) {
+				progress = 0;
+				continue;
+			}
 			if (!strcmp(arg, "--thin")) {
 				args.use_thin_pack = 1;
 				continue;
@@ -492,8 +501,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		}
 	}
 
-	if (!args.quiet)
-		args.progress = isatty(2);
+	if (progress == -1)
+		progress = !args.quiet && isatty(2);
+	args.progress = progress;
 
 	if (args.stateless_rpc) {
 		conn = NULL;
diff --git a/remote-curl.c b/remote-curl.c
index 1b5eaf30b7..7d5652f74a 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -774,6 +774,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
 		argv[argc++] = "--quiet";
 	else if (options.verbosity > 1)
 		argv[argc++] = "--verbose";
+	argv[argc++] = options.progress ? "--progress" : "--no-progress";
 	argv[argc++] = url;
 	for (i = 0; i < nr_spec; i++)
 		argv[argc++] = specs[i];

From 2f9bfc153bbcc03cca53fc6ec94bf50433b3774b Mon Sep 17 00:00:00 2001
From: Jeff King 
Date: Tue, 1 May 2012 04:43:08 -0400
Subject: [PATCH 3462/3720] t5541: test more combinations of --progress

Previously, we tested only that "push --quiet --no-progress"
was silent. However, there are many other combinations that
were not tested:

  1. no options at all (but stderr as a tty)
  2. --no-progress by itself
  3. --quiet by itself
  4. --progress (when stderr not a tty)

These are tested elsewhere for general "push", but it is
important to test them separately for http. It follows a
very different code path than git://, and options must be
relayed across a remote helper to a separate send-pack
process (and in fact cases (1), (2), and (4) have all been
broken just for http at some point in the past).

We can drop the "--quiet --no-progress" test, as it is not
really interesting (it is already handled by testing them
separately in (2) and (3) above).

Signed-off-by: Jeff King 
Signed-off-by: Johannes Schindelin 
---
 t/t5541-http-push.sh | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh
index cc6f081711..986210a082 100755
--- a/t/t5541-http-push.sh
+++ b/t/t5541-http-push.sh
@@ -215,12 +215,35 @@ test_expect_success 'push --mirror to repo with alternates' '
 	git push --mirror "$HTTPD_URL"/smart/alternates-mirror.git
 '
 
-test_expect_success TTY 'quiet push' '
+test_expect_success TTY 'push shows progress when stderr is a tty' '
+	cd "$ROOT_PATH"/test_repo_clone &&
+	test_commit noisy &&
+	test_terminal git push 2>&1 | tee output &&
+	grep "^Writing objects" output
+'
+
+test_expect_success TTY 'push --quiet silences status and progress' '
 	cd "$ROOT_PATH"/test_repo_clone &&
 	test_commit quiet &&
-	test_terminal git push --quiet --no-progress 2>&1 | tee output &&
+	test_terminal git push --quiet 2>&1 | tee output &&
 	test_cmp /dev/null output
 '
 
+test_expect_success TTY 'push --no-progress silences progress but not status' '
+	cd "$ROOT_PATH"/test_repo_clone &&
+	test_commit no-progress &&
+	test_terminal git push --no-progress 2>&1 | tee output &&
+	grep "^To http" output &&
+	! grep "^Writing objects"
+'
+
+test_expect_success 'push --progress shows progress to non-tty' '
+	cd "$ROOT_PATH"/test_repo_clone &&
+	test_commit progress &&
+	git push --progress 2>&1 | tee output &&
+	grep "^To http" output &&
+	grep "^Writing objects" output
+'
+
 stop_httpd
 test_done

From 0594e6dd25b4c8d0b8c5978583626469f0c53d11 Mon Sep 17 00:00:00 2001
From: Matthieu Moy 
Date: Sat, 14 Jan 2012 19:55:36 +0100
Subject: [PATCH 3463/3720] bash-completion: don't add quoted space for ZSH
 (fix regression)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit a31e626 (completion: optimize refs completion) introduced a
regression for ZSH users: ref names were completed with a quoted trailing
space (i.e. "git checkout ma" completes to "git checkout master\ "). The
space is convenient for bash users since we use "-o nospace", but a
quoted space is worse than nothing. The absence of trailing space for ZSH
is a long-standing issue, that this patch is not fixing. We just fix the
regression by not appending a space when the shell is ZSH.

Original-patch-by: SZEDER Gábor 
Reported-by: Stefan Haller 
Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 contrib/completion/git-completion.bash | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 9f56ec7a6b..b9d173ecf6 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -509,6 +509,13 @@ __gitcomp ()
 __gitcomp_nl ()
 {
 	local IFS=$'\n'
+
+	# ZSH would quote the trailing space added with -S. bash users
+	# will appreciate the extra space to compensate the use of -o nospace.
+	if [ -n "${ZSH_VERSION-}" ] && [ "$suffix" = " " ]; then
+		suffix=""
+	fi
+
 	COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
 }
 

From 33bef119f9359b36514b67bcb20e2d68a79e9146 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 3464/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index ac40e24625..2dabdc9789 100644
--- a/Makefile
+++ b/Makefile
@@ -1242,16 +1242,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From cd7d64ca745937cf84abf506ada174ca7db5b86f Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 3465/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 15698ba60d..3d0dc755f5 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -187,6 +187,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index e14ffcd914..fefbe9a843 100644
--- a/cache.h
+++ b/cache.h
@@ -561,6 +561,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index afc892d6b1..671a539fbd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 61a652138a..75524124a9 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -114,10 +114,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -319,6 +316,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index eeee986022..bb8b5698e7 100644
--- a/config.c
+++ b/config.c
@@ -758,6 +758,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index d7e6c65763..d827d9e71d 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index ed11ad8119..14fa4e117a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -595,4 +595,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 71d63e5bba4138f061aa5d31f77848de294fdb16 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 3466/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 671a539fbd..5d8bddb3c5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 2569127387bd42f2f4ef9eca67921b6008845968 Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 3467/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From 1ab9738ab134dfa93beaddfee18971329c84e2c8 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 3468/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From dc3ade22b4b03753ef80a91b0ae52a55cd979b92 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 3469/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From e4f613513ed773c8876b24420f27d44b67e71045 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 3470/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 22270ce46b..646fde8d10 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9575,7 +9575,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From 4a44bf810c8fd64ab569a5cfab322886bcfa8c2e Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 3471/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 50ae92b57e61576ccc17c5bb010ff36573294153 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 3472/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 8c5df5f9021cb3d0028b1a491244380198496627 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 3473/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 3d0dc755f5..963c6e739b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1797,6 +1797,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 0afb8b2896..1b2bf5fe66 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -89,7 +91,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -410,6 +417,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -441,6 +486,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -469,6 +521,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b5417cc951..2482796454 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -995,4 +995,40 @@ test_expect_success 'push --prune refspec' '
 	! check_push_result $the_first_commit tmp/foo tmp/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 8ae6011b074e4e70353722f70a61b7d5d66291fe Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 3474/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index ef30c557c7..c42fb2a7aa 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 0bd8ebe5d07e12766e81d15a9b1d034cd6ae9e0f Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 3475/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index c42fb2a7aa..03292fd832 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From bb1e0d57863faf0cd37af713c2730f20a7046a1c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 3476/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 33c8820af6..c836ad063c 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -169,7 +169,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = given_config_file;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 5d8bddb3c5..6757be9ffc 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1830,3 +1830,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory()
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 75524124a9..2fcc935b78 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -350,3 +350,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index bb8b5698e7..96661cd547 100644
--- a/config.c
+++ b/config.c
@@ -968,7 +968,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 14fa4e117a..5911e8f7eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -599,4 +599,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index 6f2aa699ad..4cb0585cde 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From 776b0f09a0f298d0dd1bee8d72b1e3fd9634a769 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 3477/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index f8b7a0cb60..11ca959c3f 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -571,7 +571,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -743,7 +744,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -819,7 +821,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -843,7 +845,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From fff27bd8d656abeed9d2e8f0e5f071b26e8bfd01 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 3478/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 9e2b71132a..32a74a6e7a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 7c7288d5e4cd532d805b136ccef707fb4b3a70eb Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 3479/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index fefbe9a843..30e9ac6190 100644
--- a/cache.h
+++ b/cache.h
@@ -729,7 +729,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 6757be9ffc..1448f48b60 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1848,3 +1848,26 @@ const char *get_windows_home_directory()
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 2fcc935b78..1e5ec25cdc 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -310,6 +310,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 5911e8f7eb..39866a76c2 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 4cb0585cde..242074b1cf 100644
--- a/path.c
+++ b/path.c
@@ -660,10 +660,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From dd878a65586b3377de34092b7d9675cdf61bfa36 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 13 Jul 2010 16:23:58 +0200
Subject: [PATCH 3480/3720] config.c: trivial fix for compile-time warning

The warning ("builtin/config.c:351: warning: initialization
discards qualifiers from pointer target type") was introduced
in commit 6754497c.

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 builtin/config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index c836ad063c..e24586efa5 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = get_home_directory();
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;

From 2c1aaf439b6ec0a30c0373434c741948e495cae2 Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 3481/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1448f48b60..e3c34e24d1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1851,23 +1851,24 @@ const char *get_windows_home_directory()
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 073e5f57379247e2e55a2b4549d9084876495c50 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 3482/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From 902f99d2b37d65a336dfd6d7cea719737a8a4f16 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 3483/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 646fde8d10..3c2864fcf2 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -394,7 +394,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9575,18 +9575,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9597,6 +9586,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From 4a68eb5f3fc62090fbbc4fdb16b0d100a341ab55 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 3484/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index e3c34e24d1..44fa8866f7 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1209,6 +1209,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 74e04bf0ee3de923afd904f56c7836235c634918 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 3485/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1e5ec25cdc..54fae7cdc6 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -291,9 +291,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From c1537a2cb869dbaf21a9b082a2b45c2ae825acf1 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 3486/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 5fb0cbdbcc2f9ccf4083b3f26fe1fa9f744ca6f5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 3487/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From ca2b2d3344266aae753144a4886a626f7d52d5a7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 3488/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index 44f0268372..d7ba20c5a7 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From c48cb2e631fb86907d6c9508c588c7cda1730c93 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 3489/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 55e0e9ea38..f9d730a93c 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4458,6 +4458,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From d4a135bc041d9850e2a618139b09d04adddf158f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 3490/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f9d730a93c..fc8cabff91 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4473,7 +4473,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From ddbd3fcf5e1461c54cdc74bea31ea0449a225d9d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 3491/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 5cb87f16f2..0270a3f883 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -138,6 +139,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From 613a587b010bcdd69a0153f852be8ab70bf610f7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 3492/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 1b2bf5fe66..b648c14a86 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -420,7 +420,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 0f4d17068d45ab7eaacf9da6c4ee84ea9d866d8b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 3493/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 643938d905..cda17f775a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -162,6 +163,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -172,6 +189,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->source.identifier))
+			continue;
+
 		opt->output_priv = w;
 		hit |= grep_source(opt, &w->source);
 		grep_source_clear_data(&w->source);
@@ -418,6 +438,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -883,6 +906,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From 40f8520bb832507129db072200c2e5372f42cb3e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 3494/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 2dabdc9789..c425ee3825 100644
--- a/Makefile
+++ b/Makefile
@@ -313,7 +313,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From 6eb5703d243bfcf0946de841ca19b202ee6a752b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:46:41 +0100
Subject: [PATCH 3495/3720] Fix old-style function declaration

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 44fa8866f7..8a2c905e6a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1835,7 +1835,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	return -1;
 }
 
-const char *get_windows_home_directory()
+const char *get_windows_home_directory(void)
 {
 	static const char *home_directory = NULL;
 	struct strbuf buf = STRBUF_INIT;

From 909586166438f1feb30d127fce68e865ee785363 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 3496/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c425ee3825..55c5976553 100644
--- a/Makefile
+++ b/Makefile
@@ -2152,7 +2152,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2192,6 +2192,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From e5de1cd4847534cee2f65fbcbc704c4306ba201d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 3497/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 8f36aa9fc4..06982bddb7 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 8554526e7b1bfc4354b209c230e737aff02b8732 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 3498/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index cda17f775a..3af417e76c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -974,6 +974,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From f5ff4073e94cdbd04aa581757cfb13531e30bf04 Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 3499/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index 497f420178..266c1236ff 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From 5894cadc0d423571df9b09f90be1d7685d2be776 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 3500/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 8a2c905e6a..cb36723e00 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From cb1c8377e0f97a78bb54c2cd1fe5e5fc35d55c77 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 3501/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From c399ab3a4631acf04bce3ef98fa0eed0f0271eef Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 3502/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 3503/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 64a70d621a..5d06d71cd1 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -836,12 +836,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 3504/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 6f33c5837124a53d7e4c858f58046c4c5ee436be Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 3505/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 7b3ae75d7a..cc6fb913ce 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$sm_path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 3506/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 55c5976553..c86eca5020 100644
--- a/Makefile
+++ b/Makefile
@@ -1236,6 +1236,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1329,6 +1330,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From 48c44a6c2fef48a70ab54e17a0696a3f5b93d198 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 3507/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 4fd75cf653c1c5424681046ebb8b4da093d49cc4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 3508/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From 98d72373da3dbb770256d509ab844128b859163d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 3509/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 3d2d7883fa60a63a33b606444e28805bd105b3e6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 3510/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From f452c0c1ae5bfe4a15910373079013fbbecae129 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 3511/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index cb36723e00..11699b9d1a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 7908621b8538c74c329873e41b0335636c9ad26e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 3512/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 11699b9d1a..1afaf931c5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1877,3 +1877,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 54fae7cdc6..9f3741ad39 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -331,22 +331,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 463cb826b554d08255573892c012e8642af73a03 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 3513/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1afaf931c5..1b3d890d4f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1878,6 +1878,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 16af47e98e409609cb4a97246070b7c4f4d4ca25 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 3514/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index fc8cabff91..8fdda5b711 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6979,7 +6979,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -7027,6 +7039,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 93309b7de9e1e925a7bff5fa0ff52040a9a6dfa0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 3515/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 8fdda5b711..2e485a0a66 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4458,7 +4458,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From c59edbd1db3d4c69d777e546104f80121064fce2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 3516/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 2e485a0a66..1f48f1d4b5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -7092,7 +7092,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From d798c3b079d98a9fa6d2a532718d97b50078bd87 Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 3517/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 1b3d890d4f..3767048a6d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From f29a12056b33d04a85f223e031f16d0f75786d57 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 3518/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index defb544ed0..7e4d30ef73 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `--rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 2a10047eb7..be1b098be0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -113,7 +114,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -278,7 +284,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From 9a15ea3e3c1c8757f49951ddd43eb3b9510aa514 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 3519/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 963c6e739b..3dc813c67e 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -717,6 +717,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index be1b098be0..34b47c4fb2 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 5bf996dffd3bdf2cab5f2064c8c5fda7de11d35f Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 3520/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 9f3741ad39..d217c3e06f 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 39866a76c2..76c5eef420 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From 72eaeef25a084a075c17a844ddbddd76b25e8ac2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 3521/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..bf514f9de5 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -30,6 +31,7 @@ static int negative;
 static FILE *last_stream = NULL;
 static int non_ascii_used = 0;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -38,6 +40,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -52,8 +55,8 @@ static void warn_if_raster_font(void)
 		return;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From 1e6d96fdc0182065f3c13e9b012ad447cf37c618 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 3522/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index c86eca5020..5dec1af5eb 100644
--- a/Makefile
+++ b/Makefile
@@ -1234,6 +1234,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From e76b8f71b4087cd5286fd4b97e7c638cc70670fe Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 3523/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index bf514f9de5..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -29,7 +29,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -45,14 +44,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
@@ -75,9 +83,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -107,8 +113,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -124,9 +128,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From 0261a74518c5da4ff02c18ca2f5f4a06e18d69ea Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 3524/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index 5dec1af5eb..7e36d64ab0 100644
--- a/Makefile
+++ b/Makefile
@@ -1312,7 +1312,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From 7994361a8a3a44040c9d007970935c433349cee7 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 3525/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 7e36d64ab0..5ac4f5403d 100644
--- a/Makefile
+++ b/Makefile
@@ -1349,6 +1349,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From 90fd7c3b7fa610476fcbfb70e60d242e0d4e2283 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 3526/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From 4ccaef8aa1a524dd675d8147a184da468bbbf2a3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 3 Feb 2012 00:12:04 -0600
Subject: [PATCH 3527/3720] Teach 'git remote' that the config var
 branch.*.rebase can be 'interactive'

Signed-off-by: Johannes Schindelin 
---
 builtin/remote.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index 0f0c594b2f..4b41e8c022 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -253,7 +253,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	int rebase;
+	enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
 };
 
 static struct string_list branch_list;
@@ -310,7 +310,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			}
 			string_list_append(&info->merge, xstrdup(value));
 		} else
-			info->rebase = git_config_bool(orig_key, value);
+			info->rebase = value && *value == 'i' ?
+				INTERACTIVE_REBASE :
+				(git_config_bool(orig_key, value) ?
+				 NORMAL_REBASE : NO_REBASE);
 	}
 	return 0;
 }
@@ -995,7 +998,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf_ln(_("rebases onto remote %s"), merge->items[0].string);
+		printf_ln(_(branch_info->rebase == INTERACTIVE_REBASE ?
+			"rebases interactively onto remote %s" :
+			"rebases onto remote %s"), merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf_ln(_(" merges with remote %s"), merge->items[0].string);

From 4f9a2279e8f96f1e60f017d73c78b829a4c88845 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:28:37 +0100
Subject: [PATCH 3528/3720] git-gui: fix encoding in git-gui file browser

Assume git tree objects (i.e. output of git-ls-tree) are encoded in system
encoding, for display in the git-gui file browser.

Signed-off-by: Karsten Blees 
---
 git-gui/lib/browser.tcl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 0328338fda..4fca8fb13c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary -encoding binary
+	fconfigure $fd -blocking 0 -translation binary
 	fileevent $fd readable [cb _read $fd]
 }
 

From 234e28c739c695158f263eb98be067a5a53405e0 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:38:07 +0100
Subject: [PATCH 3529/3720] gitk: fix file name encoding in diff hunk headers

Decode file names from system encoding in all diff hunk header lines, not
just the first (i.e. print nice file names in 'rename from' / 'rename to' /
'Binary files' lines, too).

Signed-off-by: Karsten Blees 
---
 gitk-git/gitk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 3c2864fcf2..16ff52a2c1 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7855,6 +7855,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
+	    set line [encoding convertfrom $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {

From a9133cc4b5c87eea20e4d8df95a88d7a07cfa64d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 19:06:41 +0100
Subject: [PATCH 3530/3720] Revert "Windows: teach getenv to do a
 case-sensitive search"

This reverts commit df599e9612788b728ce43a03159b85f1fe624d6a.

As of 5e9637c6 "i18n: add infrastructure for translating Git with gettext",
eval_gettext uses MinGW envsubst.exe instead of git-sh-i18n--envsubst.exe
for variable substitution. This breaks git-submodule.sh messages and tests,
as envsubst.exe doesn't support case-sensitive environment lookup (the same
is true for almost everything on Windows, including MSys and Cygwin tools).

30a615ac "Windows/i18n: rename $path to prevent clashes with $PATH" renames
the conflicting variable in git-submodule.sh, so that it works on Windows
(i.e. with case-insensitive environment, regardless of the toolset).

Revert to the documented behaviour of case-insensitive environment on
Windows.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 3767048a6d..17ed1f7ad5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1184,31 +1184,14 @@ char **make_augmented_environ(const char *const *vars)
 }
 
 #undef getenv
-
-/*
- * The system's getenv looks up the name in a case-insensitive manner.
- * This version tries a case-sensitive lookup and falls back to
- * case-insensitive if nothing was found.  This is necessary because,
- * as a prominent example, CMD sets 'Path', but not 'PATH'.
- * Warning: not thread-safe.
- */
-static char *getenv_cs(const char *name)
-{
-	size_t len = strlen(name);
-	int i = lookup_env(environ, name, len);
-	if (i >= 0)
-		return environ[i] + len + 1;	/* skip past name and '=' */
-	return getenv(name);
-}
-
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv_cs(name);
+	char *result = getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv_cs("TMP");
+		result = getenv("TMP");
 		if (!result)
-			result = getenv_cs("TEMP");
+			result = getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */

From d2202ea8137758ec9da1b57bfdb06f473f1292a2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:19:31 +0100
Subject: [PATCH 3531/3720] Revert "mingw.c: move definition of mingw_getenv
 down"

This reverts commit 06bc4b796ad69ba93f0a8c451368602e0553c2d3.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 17ed1f7ad5..e1f7a3b0b5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -180,7 +180,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	vsnprintf(question, sizeof(question), format, args);
 	va_end(args);
 
-	if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
+	if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
 		retry_hook[1] = question;
 		return !run_command_v_opt(retry_hook, 0);
 	}
@@ -665,6 +665,23 @@ char *mingw_getcwd(char *pointer, int len)
 	return ret;
 }
 
+#undef getenv
+char *mingw_getenv(const char *name)
+{
+	char *result = getenv(name);
+	if (!result && !strcmp(name, "TMPDIR")) {
+		/* on Windows it is TMP and TEMP */
+		result = getenv("TMP");
+		if (!result)
+			result = getenv("TEMP");
+	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
+	return result;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -764,7 +781,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-	char *p, **path, *envpath = mingw_getenv("PATH");
+	char *p, **path, *envpath = getenv("PATH");
 	int i, n = 0;
 
 	if (!envpath || !*envpath)
@@ -1183,23 +1200,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-	char *result = getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
-		if (!result)
-			result = getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 5fea0ad68083da6c4d0e3874826629df3721b496 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:24:19 +0100
Subject: [PATCH 3532/3720] Win32: Thread-safe windows console output

Winansi.c has many static variables that are accessed and modified from
the [v][f]printf / fputs functions overridden in the file. This may cause
multi threaded git commands that print to the console to produce corrupted
output or even crash.

Additionally, winansi.c doesn't override all functions that can be used to
print to the console (e.g. fwrite, write, fputc are missing), so that ANSI
escapes don't work properly for some git commands (e.g. git-grep).

Instead of doing ANSI emulation in just a few wrapped functions on top of
the IO API, let's plug into the IO system and take advantage of the thread
safety inherent to the IO system.

Redirect stdout and stderr to a pipe if they point to the console. A
background thread reads from the pipe, handles ANSI escape sequences and
UTF-8 to UTF-16 conversion, then writes to the console.

The pipe-based stdout and stderr replacements must be set to unbuffered, as
MSVCRT doesn't support line buffering and fully buffered streams are
inappropriate for console output.

Due to the byte-oriented pipe, ANSI escape sequences and multi-byte UTF-8
sequences can no longer be expected to arrive in one piece. Replace the
string-based ansi_emulate() with a simple stateful parser (this also fixes
colored diff hunk headers, which were broken as of commit 2efcc977).

Override isatty to return true for the pipes redirecting to the console.

Exec/spawn obtain the original console handle to pass to the next process
via winansi_get_osfhandle().

All other overrides are gone, the default stdio implementations work as
expected with the piped stdout/stderr descriptors.

Global variables are either initialized on startup (single threaded) or
exclusively modified by the background thread. Threads communicate through
the pipe, no further synchronization is necessary.

The background thread is terminated by disonnecting the pipe after flushing
the stdio and pipe buffers. This doesn't work for anonymous pipes (created
via CreatePipe), as DisconnectNamedPipe only works on the read end, which
discards remaining data. Thus we have to setup the pipe manually, with the
write end beeing the server (opened with CreateNamedPipe) and the read end
the client (opened with CreateFile).

Limitations: doesn't track reopened or duped file descriptors, i.e.:
- fdopen(1/2) returns fully buffered streams
- dup(1/2), dup2(1/2) returns normal pipe descriptors (i.e. isatty() =
  false, winansi_get_osfhandle won't return the original console handle)

Currently, only the git-format-patch command uses xfdopen(xdup(1)) (see
"realstdout" in builtin/log.c), but works well with these limitations.

Many thanks to Atsushi Nakagawa  for suggesting and
reviewing the thread-exit-mechanism.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c   |   9 +-
 compat/mingw.h   |  12 +-
 compat/winansi.c | 420 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 282 insertions(+), 159 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e1f7a3b0b5..ee37201815 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -917,9 +917,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	memset(&si, 0, sizeof(si));
 	si.cb = sizeof(si);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-	si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-	si.hStdError = (HANDLE) _get_osfhandle(fherr);
+	si.hStdInput = winansi_get_osfhandle(fhin);
+	si.hStdOutput = winansi_get_osfhandle(fhout);
+	si.hStdError = winansi_get_osfhandle(fherr);
 
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
@@ -1880,4 +1880,7 @@ void mingw_startup()
 	_setmode(_fileno(stdin), _O_BINARY);
 	_setmode(_fileno(stdout), _O_BINARY);
 	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
 }
diff --git a/compat/mingw.h b/compat/mingw.h
index d217c3e06f..ecab854b99 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -289,14 +289,10 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-int winansi_vfprintf(FILE *stream, const char *format, va_list list);
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
-#define vfprintf winansi_vfprintf
+void winansi_init(void);
+int winansi_isatty(int fd);
+HANDLE winansi_get_osfhandle(int fd);
+#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index bec6713b74..a3e4d88295 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,18 +4,13 @@
 
 #undef NOGDI
 #include "../git-compat-util.h"
-#include 
 #include 
 #include 
 
 /*
  Functions to be wrapped:
 */
-#undef printf
-#undef fprintf
-#undef fputs
-#undef vfprintf
-/* TODO: write */
+#undef isatty
 
 /*
  ANSI codes used by git: m, K
@@ -28,7 +23,10 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
-static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hwrite1 = INVALID_HANDLE_VALUE, hwrite2 = INVALID_HANDLE_VALUE;
+static HANDLE hconsole1, hconsole2;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -44,27 +42,19 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void print_font_warning(void)
+static void warn_if_raster_font(void)
 {
-	warning("Your console font probably doesn\'t support Unicode. If "
-		"you experience strange characters in the output, consider "
-		"switching to a TrueType font such as Lucida Console!");
-}
-
-static void check_truetype_font(void)
-{
-	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't do this twice */
-	if (truetype_font_checked)
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
 		return;
-	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
+			GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);
@@ -73,8 +63,8 @@ static void check_truetype_font(void)
 	} else {
 		/* pre-Vista: check default console font in registry */
 		HKEY hkey;
-		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
-				KEY_READ, &hkey)) {
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+				0, KEY_READ, &hkey)) {
 			DWORD size = sizeof(fontFamily);
 			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
 					(LPVOID) &fontFamily, &size);
@@ -82,61 +72,63 @@ static void check_truetype_font(void)
 		}
 	}
 
-	if (!(fontFamily & TMPF_TRUETYPE))
-		atexit(print_font_warning);
+	if (!(fontFamily & TMPF_TRUETYPE)) {
+		const wchar_t *msg = L"\nWarning: Your console font probably "
+			L"doesn\'t support Unicode. If you experience strange "
+			L"characters in the output, consider switching to a "
+			L"TrueType font such as Lucida Console!\n";
+		WriteConsoleW(console, msg, wcslen(msg), NULL, NULL);
+	}
 }
 
-static int is_console(FILE *stream)
+static int is_console(int fd)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
 	HANDLE hcon;
 
 	static int initialized = 0;
 
-	/* use cached value if stream hasn't changed */
-	if (stream == last_stream)
-		return console != NULL;
-
-	last_stream = stream;
-	console = NULL;
-
-	/* get OS handle of the stream */
-	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	/* get OS handle of the file descriptor */
+	hcon = (HANDLE) _get_osfhandle(fd);
 	if (hcon == INVALID_HANDLE_VALUE)
 		return 0;
 
+	/* check if its a device (i.e. console, printer, serial port) */
+	if (GetFileType(hcon) != FILE_TYPE_CHAR)
+		return 0;
+
 	/* check if its a handle to a console output screen buffer */
 	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
+	/* initialize attributes */
 	if (!initialized) {
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
 	}
 
-	console = hcon;
 	return 1;
 }
 
-static int write_console(const char *str, size_t len)
-{
-	/* convert utf-8 to utf-16, write directly to console */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
-	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
-	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
 
+static void write_console(unsigned char *str, size_t len)
+{
+	/* only called from console_thread, so a static buffer will do */
+	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+
+	/* convert utf-8 to utf-16 */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
+			ARRAY_SIZE(wbuf));
+
+	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/*
-	 * if non-ascii characters are printed, check that the current console
-	 * font supports this
-	 */
+	/* remember if non-ascii characters are printed */
 	if (wlen != len)
-		check_truetype_font();
-
-	/* return original (utf-8 encoded) length */
-	return len;
+		non_ascii_used = 1;
 }
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
@@ -182,18 +174,13 @@ static void erase_in_line(void)
 		&dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-	const char *func;
-	size_t len = strspn(str, "0123456789;");
-	func = str + len;
-
-	switch (*func) {
+	int i;
+	switch (func) {
 	case 'm':
-		do {
-			long val = strtol(str, (char **)&str, 10);
-			switch (val) {
+		for (i = 0; i < paramlen; i++) {
+			switch (params[i]) {
 			case 0: /* reset */
 				attr = plain_attr;
 				negative = 0;
@@ -316,9 +303,7 @@ static const char *set_attr(const char *str)
 				/* Unsupported code */
 				break;
 			}
-			str++;
-		} while (*(str-1) == ';');
-
+		}
 		set_console_attr();
 		break;
 	case 'K':
@@ -328,112 +313,251 @@ static const char *set_attr(const char *str)
 		/* Unsupported code */
 		break;
 	}
-
-	return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+	TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-	int rv = 0;
-	const char *pos = str;
+	unsigned char buffer[BUFFER_SIZE];
+	DWORD bytes;
+	int start, end = 0, c, parampos = 0, state = TEXT;
+	int params[MAX_PARAMS];
 
-	fflush(stream);
+	while (1) {
+		/* read next chunk of bytes from the pipe */
+		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+				NULL)) {
+			/* exit if pipe has been closed or disconnected */
+			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+					GetLastError() == ERROR_BROKEN_PIPE)
+				break;
+			/* ignore other errors */
+			continue;
+		}
 
-	while (*pos) {
-		pos = strstr(str, "\033[");
-		if (pos) {
-			size_t len = pos - str;
+		/* scan the bytes and handle ANSI control codes */
+		bytes += end;
+		start = end = 0;
+		while (end < bytes) {
+			c = buffer[end++];
+			switch (state) {
+			case TEXT:
+				if (c == ESCAPE) {
+					/* print text seen so far */
+					if (end - 1 > start)
+						write_console(buffer + start,
+							end - 1 - start);
 
-			if (len) {
-				size_t out_len = write_console(str, len);
-				rv += out_len;
-				if (out_len < len)
-					return rv;
+					/* then start parsing escape sequence */
+					start = end - 1;
+					memset(params, 0, sizeof(params));
+					parampos = 0;
+					state = ESCAPE;
+				}
+				break;
+
+			case ESCAPE:
+				/* continue if "\033[", otherwise bail out */
+				state = (c == BRACKET) ? BRACKET : TEXT;
+				break;
+
+			case BRACKET:
+				/* parse [0-9;]* into array of parameters */
+				if (c >= '0' && c <= '9') {
+					params[parampos] *= 10;
+					params[parampos] += c - '0';
+				} else if (c == ';') {
+					/*
+					 * next parameter, bail out if out of
+					 * bounds
+					 */
+					parampos++;
+					if (parampos >= MAX_PARAMS)
+						state = TEXT;
+				} else {
+					/*
+					 * end of escape sequence, change
+					 * console attributes
+					 */
+					set_attr(c, params, parampos + 1);
+					start = end;
+					state = TEXT;
+				}
+				break;
+			}
+		}
+
+		/* print remaining text unless parsing an escape sequence */
+		if (state == TEXT && end > start) {
+			/* check for incomplete UTF-8 sequences and fix end */
+			if (buffer[end - 1] >= 0x80) {
+				if (buffer[end -1] >= 0xc0)
+					end--;
+				else if (end - 1 > start &&
+						buffer[end - 2] >= 0xe0)
+					end -= 2;
+				else if (end - 2 > start &&
+						buffer[end - 3] >= 0xf0)
+					end -= 3;
 			}
 
-			str = pos + 2;
-			rv += 2;
+			/* print remaining complete UTF-8 sequences */
+			if (end > start)
+				write_console(buffer + start, end - start);
 
-			pos = set_attr(str);
-			rv += pos - str;
-			str = pos;
+			/* move remaining bytes to the front */
+			if (end < bytes)
+				memmove(buffer, buffer + end, bytes - end);
+			end = bytes - end;
 		} else {
-			size_t len = strlen(str);
-			rv += write_console(str, len);
-			return rv;
+			/* all data has been consumed, mark buffer empty */
+			end = 0;
 		}
 	}
-	return rv;
+
+	/* check if the console font supports unicode */
+	warn_if_raster_font();
+
+	CloseHandle(hread);
+	return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-	int rv;
+	/* flush all streams */
+	_flushall();
 
-	if (!is_console(stream))
-		return fputs(str, stream);
+	/* signal console thread to exit */
+	FlushFileBuffers(hwrite);
+	DisconnectNamedPipe(hwrite);
 
-	rv = ansi_emulate(str, stream);
+	/* wait for console thread to copy remaining data */
+	WaitForSingleObject(hthread, INFINITE);
 
-	if (rv >= 0)
-		return 0;
+	/* cleanup handles... */
+	if (hwrite1 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite1);
+	if (hwrite2 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite2);
+	CloseHandle(hwrite);
+	CloseHandle(hthread);
+}
+
+static void die_lasterr(const char *fmt, ...)
+{
+	va_list params;
+	va_start(params, fmt);
+	errno = err_win_to_posix(GetLastError());
+	die_errno(fmt, params);
+	va_end(params);
+}
+
+static HANDLE duplicate_handle(HANDLE hnd)
+{
+	HANDLE hresult, hproc = GetCurrentProcess();
+	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+			DUPLICATE_SAME_ACCESS))
+		die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+	return hresult;
+}
+
+static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+{
+	/* get original console handle */
+	int fd = _fileno(stream);
+	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
+	if (hcon == INVALID_HANDLE_VALUE)
+		die_errno("_get_osfhandle(%i) failed", fd);
+
+	/* save a copy to phcon and console (used by the background thread) */
+	console = *phcon = duplicate_handle(hcon);
+
+	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
+	if (_dup2(new_fd, fd))
+		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+
+	/* no buffering, or stdout / stderr will be out of sync */
+	setbuf(stream, NULL);
+	return (HANDLE) _get_osfhandle(fd);
+}
+
+void winansi_init(void)
+{
+	int con1, con2, hwrite_fd;
+	char name[32];
+
+	/* check if either stdout or stderr is a console output screen buffer */
+	con1 = is_console(1);
+	con2 = is_console(2);
+	if (!con1 && !con2)
+		return;
+
+	/* create a named pipe to communicate with the console thread */
+	sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+	hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+	if (hwrite == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateNamedPipe failed");
+
+	hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (hread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateFile for named pipe failed");
+
+	/* start console spool thread on the pipe's read end */
+	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+	if (hthread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateThread(console_thread) failed");
+
+	/* schedule cleanup routine */
+	if (atexit(winansi_exit))
+		die_errno("atexit(winansi_exit) failed");
+
+	/* create a file descriptor for the write end of the pipe */
+	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
+	if (hwrite_fd == -1)
+		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
+
+	/* redirect stdout / stderr to the pipe */
+	if (con1)
+		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+	if (con2)
+		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
+
+	/* close pipe file descriptor (also closes the duped hwrite) */
+	close(hwrite_fd);
+}
+
+static int is_same_handle(HANDLE hnd, int fd)
+{
+	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
+}
+
+/*
+ * Return true if stdout / stderr is a pipe redirecting to the console.
+ */
+int winansi_isatty(int fd)
+{
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return 1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return 1;
 	else
-		return EOF;
+		return isatty(fd);
 }
 
-int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-	int len, rv;
-	char small_buf[256];
-	char *buf = small_buf;
-	va_list cp;
-
-	if (!is_console(stream))
-		goto abort;
-
-	va_copy(cp, list);
-	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-	va_end(cp);
-
-	if (len > sizeof(small_buf) - 1) {
-		buf = malloc(len + 1);
-		if (!buf)
-			goto abort;
-
-		len = vsnprintf(buf, len + 1, format, list);
-	}
-
-	rv = ansi_emulate(buf, stream);
-
-	if (buf != small_buf)
-		free(buf);
-	return rv;
-
-abort:
-	rv = vfprintf(stream, format, list);
-	return rv;
-}
-
-int winansi_fprintf(FILE *stream, const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stream, format, list);
-	va_end(list);
-
-	return rv;
-}
-
-int winansi_printf(const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stdout, format, list);
-	va_end(list);
-
-	return rv;
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return hconsole1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return hconsole2;
+	else
+		return (HANDLE) _get_osfhandle(fd);
 }

From b4a70030d0e6bd4bc40672de5bca695852a4f30c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:05:06 +0100
Subject: [PATCH 3533/3720] Win32: add Unicode conversion functions

Add Unicode conversion functions to convert between Windows native UTF-16LE
encoding to UTF-8 and back.

To support repositories with legacy-encoded file names, the UTF-8 to UTF-16
conversion function tries to create valid, unique file names even for
invalid UTF-8 byte sequences, so that these repositories can be checked out
without error.

The current implementation leaves invalid UTF-8 bytes in range 0xa0 - 0xff
as is (producing printable Unicode chars \u00a0 - \u00ff, equivalent to
ISO-8859-1), and converts 0x80 - 0x9f to hex-code (\u0080 - \u009f are
control chars).

The Windows MultiByteToWideChar API was not used as it either drops invalid
UTF-8 sequences (on Win2k/XP; producing non-unique or even empty file
names) or converts them to the replacement char \ufffd (Vista/7; causing
ERROR_INVALID_NAME in subsequent calls to file system APIs).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c |  85 ++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index ee37201815..9cd188e170 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1861,6 +1861,91 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
diff --git a/compat/mingw.h b/compat/mingw.h
index ecab854b99..c8285e8081 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -327,6 +327,110 @@ void mingw_mark_as_git_dir(const char *dir);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A replacement of main() that adds win32 specific initialization.
  */

From 4c901b8bf7190df0955882fd41b0c2a0b01a6071 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 18:21:28 +0100
Subject: [PATCH 3534/3720] Win32: Unicode file name support (except dirent)

Replaces Windows "ANSI" APIs dealing with file- or path names with their
Unicode equivalent, adding UTF-8/UTF-16LE conversion as necessary.

The dirent API (opendir/readdir/closedir) is updated in a separate commit.

Adds trivial wrappers for access, chmod and chdir.

Adds wrapper for mktemp (needed for both mkstemp and mkdtemp).

The simplest way to convert a repository with legacy-encoded (e.g. Cp1252)
file names to UTF-8 ist to checkout with an old msysgit version and
"git add --all & git commit" with the new version.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 210 ++++++++++++++++++++++++++++++++++---------------
 compat/mingw.h |  13 +++
 2 files changed, 158 insertions(+), 65 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9cd188e170..d81e9c02c1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "win32.h"
 #include 
+#include 
 #include "../strbuf.h"
 #include "../run-command.h"
 #include "../cache.h"
@@ -200,14 +201,16 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	}
 }
 
-#undef unlink
 int mingw_unlink(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
 	/* read-only files cannot be removed */
-	chmod(pathname, 0666);
-	while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
 		/*
@@ -223,43 +226,40 @@ int mingw_unlink(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = unlink(pathname);
+	       ret = _wunlink(wpathname);
 	return ret;
 }
 
-static int is_dir_empty(const char *path)
+static int is_dir_empty(const wchar_t *wpath)
 {
-	struct strbuf buf = STRBUF_INIT;
-	WIN32_FIND_DATAA findbuf;
+	WIN32_FIND_DATAW findbuf;
 	HANDLE handle;
-
-	strbuf_addf(&buf, "%s\\*", path);
-	handle = FindFirstFileA(buf.buf, &findbuf);
-	if (handle == INVALID_HANDLE_VALUE) {
-		strbuf_release(&buf);
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
 		return GetLastError() == ERROR_NO_MORE_FILES;
-	}
 
-	while (!strcmp(findbuf.cFileName, ".") ||
-			!strcmp(findbuf.cFileName, ".."))
-		if (!FindNextFile(handle, &findbuf)) {
-			strbuf_release(&buf);
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf))
 			return GetLastError() == ERROR_NO_MORE_FILES;
-		}
 	FindClose(handle);
-	strbuf_release(&buf);
 	return 0;
 }
 
-#undef rmdir
 int mingw_rmdir(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
-	while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
-		if (!is_dir_empty(pathname)) {
+		if (!is_dir_empty(wpathname)) {
 			errno = ENOTEMPTY;
 			break;
 		}
@@ -276,14 +276,14 @@ int mingw_rmdir(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = rmdir(pathname);
+	       ret = _wrmdir(wpathname);
 	return ret;
 }
 
-static int make_hidden(const char *path)
+static int make_hidden(const wchar_t *path)
 {
-	DWORD attribs = GetFileAttributes(path);
-	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+	DWORD attribs = GetFileAttributesW(path);
+	if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
 		return 0;
 	errno = err_win_to_posix(GetLastError());
 	return -1;
@@ -291,19 +291,23 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
-	    make_hidden(dir))
-		warning("Failed to make '%s' hidden", dir);
+	wchar_t wdir[MAX_PATH];
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
+		if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
+			warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
 		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
 		 "dotGitOnly" : "true"));
 }
 
-#undef mkdir
 int mingw_mkdir(const char *path, int mode)
 {
-	int ret = mkdir(path);
+	int ret;
+	wchar_t wpath[MAX_PATH];
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
 	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
 		/*
 		 * In Windows a file or dir starting with a dot is not
@@ -312,17 +316,17 @@ int mingw_mkdir(const char *path, int mode)
 		 */
 		const char *start = basename((char*)path);
 		if (*start == '.')
-			return make_hidden(path);
+			return make_hidden(wpath);
 	}
 	return ret;
 }
 
-#undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
 	va_list args;
 	unsigned mode;
 	int fd;
+	wchar_t wfilename[MAX_PATH];
 
 	va_start(args, oflags);
 	mode = va_arg(args, int);
@@ -331,10 +335,12 @@ int mingw_open (const char *filename, int oflags, ...)
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
 
-	fd = open(filename, oflags, mode);
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	fd = _wopen(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
-		DWORD attrs = GetFileAttributes(filename);
+		DWORD attrs = GetFileAttributesW(wfilename);
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
@@ -346,7 +352,7 @@ int mingw_open (const char *filename, int oflags, ...)
 		 * such a file is created.
 		 */
 		const char *start = basename((char*)filename);
-		if (*start == '.' && make_hidden(filename))
+		if (*start == '.' && make_hidden(wfilename))
 			warning("Could not mark '%s' as hidden.", filename);
 	}
 	return fd;
@@ -369,38 +375,69 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 	return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
-#undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = fopen(filename, otype);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfopen(wfilename, wotype);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
-#undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = freopen(filename, otype, stream);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -426,10 +463,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
  */
 static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
-	int err;
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
-	if (!(err = get_file_attr(file_name, &fdata))) {
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
 		buf->st_ino = 0;
 		buf->st_gid = 0;
 		buf->st_uid = 0;
@@ -442,8 +481,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-			WIN32_FIND_DATAA findbuf;
-			HANDLE handle = FindFirstFileA(file_name, &findbuf);
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
 			if (handle != INVALID_HANDLE_VALUE) {
 				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
 						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
@@ -462,7 +501,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		}
 		return 0;
 	}
-	errno = err;
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	default:
+		errno = ENOENT;
+		break;
+	}
 	return -1;
 }
 
@@ -551,16 +606,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
 {
 	FILETIME mft, aft;
 	int fh, rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
 	/* must have write permission */
-	DWORD attrs = GetFileAttributes(file_name);
+	attrs = GetFileAttributesW(wfilename);
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors here; open() will report them */
-		SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
 	}
 
-	if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+	if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
 		rc = -1;
 		goto revert_attrs;
 	}
@@ -583,7 +642,7 @@ revert_attrs:
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors again */
-		SetFileAttributes(file_name, attrs);
+		SetFileAttributesW(wfilename, attrs);
 	}
 	return rc;
 }
@@ -594,6 +653,18 @@ unsigned int sleep (unsigned int seconds)
 	return 0;
 }
 
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
 int mkstemp(char *template)
 {
 	char *filename = mktemp(template);
@@ -652,17 +723,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
 	return result;
 }
 
-#undef getcwd
 char *mingw_getcwd(char *pointer, int len)
 {
 	int i;
-	char *ret = getcwd(pointer, len);
-	if (!ret)
-		return ret;
+	wchar_t wpointer[MAX_PATH];
+	if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+		return NULL;
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
 	for (i = 0; pointer[i]; i++)
 		if (pointer[i] == '\\')
 			pointer[i] = '/';
-	return ret;
+	return pointer;
 }
 
 #undef getenv
@@ -1497,33 +1569,36 @@ int mingw_rename(const char *pold, const char *pnew)
 {
 	DWORD attrs, gle;
 	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+		return -1;
 
 	/*
 	 * Try native rename() first to get errno right.
 	 * It is based on MoveFile(), which cannot overwrite existing files.
 	 */
-	if (!rename(pold, pnew))
+	if (!_wrename(wpold, wpnew))
 		return 0;
 	if (errno != EEXIST)
 		return -1;
 repeat:
-	if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 		return 0;
 	/* TODO: translate more errors */
 	gle = GetLastError();
 	if (gle == ERROR_ACCESS_DENIED &&
-	    (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
 		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
 			errno = EISDIR;
 			return -1;
 		}
 		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
-		    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
-			if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 				return 0;
 			gle = GetLastError();
 			/* revert file attributes on failure */
-			SetFileAttributes(pnew, attrs);
+			SetFileAttributesW(wpnew, attrs);
 		}
 	}
 	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
@@ -1733,11 +1808,16 @@ void mingw_open_html(const char *unixpath)
 
 int link(const char *oldpath, const char *newpath)
 {
-	typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+	typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
 	static T create_hard_link = NULL;
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
 	if (!create_hard_link) {
 		create_hard_link = (T) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+			GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
 		if (!create_hard_link)
 			create_hard_link = (T)-1;
 	}
@@ -1745,7 +1825,7 @@ int link(const char *oldpath, const char *newpath)
 		errno = ENOSYS;
 		return -1;
 	}
-	if (!create_hard_link(newpath, oldpath, NULL)) {
+	if (!create_hard_link(wnewpath, woldpath, NULL)) {
 		errno = err_win_to_posix(GetLastError());
 		return -1;
 	}
diff --git a/compat/mingw.h b/compat/mingw.h
index c8285e8081..11928fc835 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -183,6 +183,19 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 

From e1897fe40d68e3fea8621e068cb598ed853c8777 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:01:09 +0100
Subject: [PATCH 3535/3720] Win32: Unicode file name support (dirent)

Changes opendir/readdir to use Windows Unicode APIs and convert between
UTF-8/UTF-16.

Removes parameter checks that are already covered by xutftowcs_path. This
changes detection of ENAMETOOLONG from MAX_PATH - 2 to MAX_PATH (matching
is_dir_empty in mingw.c). If name + "/*" or the resulting absolute path is
too long, FindFirstFile fails and errno is set through err_win_to_posix.

Increases the size of dirent.d_name to accommodate the full
WIN32_FIND_DATA.cFileName converted to UTF-8 (UTF-16 to UTF-8 conversion
may grow by factor three in the worst case).

Signed-off-by: Karsten Blees 
---
 compat/win32/dirent.c | 30 ++++++++++--------------------
 compat/win32/dirent.h |  2 +-
 2 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 82a515c21b..52420ec7d4 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -6,10 +6,10 @@ struct DIR {
 	int dd_stat;          /* 0-based index */
 };
 
-static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
 {
-	/* copy file name from WIN32_FIND_DATA to dirent */
-	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+	/* convert UTF-16 name to UTF-8 */
+	xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
 
 	/* Set file type, based on WIN32_FIND_DATA */
 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -20,25 +20,15 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
 
 DIR *opendir(const char *name)
 {
-	char pattern[MAX_PATH];
-	WIN32_FIND_DATAA fdata;
+	wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
+	WIN32_FIND_DATAW fdata;
 	HANDLE h;
 	int len;
 	DIR *dir;
 
-	/* check that name is not NULL */
-	if (!name) {
-		errno = EINVAL;
+	/* convert name to UTF-16 and check length < MAX_PATH */
+	if ((len = xutftowcs_path(pattern, name)) < 0)
 		return NULL;
-	}
-	/* check that the pattern won't be too long for FindFirstFileA */
-	len = strlen(name);
-	if (len + 2 >= MAX_PATH) {
-		errno = ENAMETOOLONG;
-		return NULL;
-	}
-	/* copy name to temp buffer */
-	memcpy(pattern, name, len + 1);
 
 	/* append optional '/' and wildcard '*' */
 	if (len && !is_dir_sep(pattern[len - 1]))
@@ -47,7 +37,7 @@ DIR *opendir(const char *name)
 	pattern[len] = 0;
 
 	/* open find handle */
-	h = FindFirstFileA(pattern, &fdata);
+	h = FindFirstFileW(pattern, &fdata);
 	if (h == INVALID_HANDLE_VALUE) {
 		DWORD err = GetLastError();
 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
@@ -72,8 +62,8 @@ struct dirent *readdir(DIR *dir)
 	/* if first entry, dirent has already been set up by opendir */
 	if (dir->dd_stat) {
 		/* get next entry and convert from WIN32_FIND_DATA to dirent */
-		WIN32_FIND_DATAA fdata;
-		if (FindNextFileA(dir->dd_handle, &fdata)) {
+		WIN32_FIND_DATAW fdata;
+		if (FindNextFileW(dir->dd_handle, &fdata)) {
 			finddata2dirent(&dir->dd_dir, &fdata);
 		} else {
 			DWORD lasterr = GetLastError();
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 8838cd61fc..058207e4bf 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,7 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
-	char d_name[MAX_PATH];     /* file name */
+	char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
 };
 
 DIR *opendir(const char *dirname);

From 6423335433aaf89f4d011e22ffd119aa54661bfc Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 4 Feb 2012 21:54:36 +0100
Subject: [PATCH 3536/3720] Unicode file name support (gitk and git-gui)

Assumes file names in git tree objects are UTF-8 encoded.

On most unix systems, the system encoding (and thus the TCL system
encoding) will be UTF-8, so file names will be displayed correctly.

On Windows, it is impossible to set the system encoding to UTF-8. Changing
the TCL system encoding (via 'encoding system ...', e.g. in the startup
code) is explicitly discouraged by the TCL docs.

Change gitk and git-gui functions dealing with file names to always convert
from and to UTF-8.

Signed-off-by: Karsten Blees 
---
 git-gui/git-gui.sh      | 11 +++++++----
 git-gui/lib/browser.tcl |  2 +-
 git-gui/lib/index.tcl   |  6 +++---
 gitk-git/gitk           | 16 ++++++++--------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index a59020bcc5..e5038ddd12 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -533,6 +533,9 @@ proc git {args} {
 
 	_trace_exec [concat $opt $cmdp $args]
 	set result [eval exec $opt $cmdp $args]
+	if {[encoding system] != "utf-8"} {
+		set result [encoding convertfrom utf-8 [encoding convertto $result]]
+	}
 	if {$::_trace} {
 		puts stderr "< $result"
 	}
@@ -1087,7 +1090,7 @@ git-version proc _parse_config {arr_name args} {
 				[list git_read config] \
 				$args \
 				[list --null --list]]
-			fconfigure $fd_rc -translation binary
+			fconfigure $fd_rc -translation binary -encoding utf-8
 			set buf [read $fd_rc]
 			close $fd_rc
 		}
@@ -1652,7 +1655,7 @@ proc read_diff_index {fd after} {
 		set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			[lindex $i 4]? \
 			[list [lindex $i 0] [lindex $i 2]] \
 			[list]
@@ -1685,7 +1688,7 @@ proc read_diff_files {fd after} {
 		set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			?[lindex $i 4] \
 			[list] \
 			[list [lindex $i 0] [lindex $i 2]]
@@ -1708,7 +1711,7 @@ proc read_ls_others {fd after} {
 	set pck [split $buf_rlo "\0"]
 	set buf_rlo [lindex $pck end]
 	foreach p [lrange $pck 0 end-1] {
-		set p [encoding convertfrom $p]
+		set p [encoding convertfrom utf-8 $p]
 		if {[string index $p end] eq {/}} {
 			set p [string range $p 0 end-1]
 		}
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 4fca8fb13c..555db896f4 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary
+	fconfigure $fd -blocking 0 -translation binary -encoding utf-8
 	fileevent $fd readable [cb _read $fd]
 }
 
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdde21..6ca0a6e369 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -115,7 +115,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
 		set info [lindex $s 2]
 		if {$info eq {}} continue
 
-		puts -nonewline $fd "$info\t[encoding convertto $path]\0"
+		puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -186,7 +186,7 @@ proc write_update_index {fd pathList totalCnt batch after} {
 		?M {set new M_}
 		?? {continue}
 		}
-		puts -nonewline $fd "[encoding convertto $path]\0"
+		puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -247,7 +247,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
 		?M -
 		?T -
 		?D {
-			puts -nonewline $fd "[encoding convertto $path]\0"
+			puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 			display_file $path ?_
 		}
 		}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 16ff52a2c1..59693c0005 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7329,7 +7329,7 @@ proc gettreeline {gtf id} {
 	if {[string index $fname 0] eq "\""} {
 	    set fname [lindex $fname 0]
 	}
-	set fname [encoding convertfrom $fname]
+	set fname [encoding convertfrom utf-8 $fname]
 	lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -7551,7 +7551,7 @@ proc gettreediffline {gdtf ids} {
 	    if {[string index $file 0] eq "\""} {
 		set file [lindex $file 0]
 	    }
-	    set file [encoding convertfrom $file]
+	    set file [encoding convertfrom utf-8 $file]
 	    if {$file ne [lindex $treediff end]} {
 		lappend treediff $file
 		lappend sublist $file
@@ -7700,7 +7700,7 @@ proc makediffhdr {fname ids} {
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -7734,7 +7734,7 @@ proc getblobdiffline {bdf ids} {
 	}
 	if {![string compare -length 5 "diff " $line]} {
 	    if {![regexp {^diff (--cc|--git) } $line m type]} {
-		set line [encoding convertfrom $line]
+		set line [encoding convertfrom utf-8 $line]
 		$ctext insert end "$line\n" hunksep
 		continue
 	    }
@@ -7781,7 +7781,7 @@ proc getblobdiffline {bdf ids} {
 	    makediffhdr $fname $ids
 
 	} elseif {![string compare -length 16 "* Unmerged path " $line]} {
-	    set fname [encoding convertfrom [string range $line 16 end]]
+	    set fname [encoding convertfrom utf-8 [string range $line 16 end]]
 	    $ctext insert end "\n"
 	    set curdiffstart [$ctext index "end - 1c"]
 	    lappend ctext_file_names $fname
@@ -7836,7 +7836,7 @@ proc getblobdiffline {bdf ids} {
 		if {[string index $fname 0] eq "\""} {
 		    set fname [lindex $fname 0]
 		}
-		set fname [encoding convertfrom $fname]
+		set fname [encoding convertfrom utf-8 $fname]
 		set i [lsearch -exact $treediffs($ids) $fname]
 		if {$i >= 0} {
 		    setinlist difffilestart $i $curdiffstart
@@ -7855,7 +7855,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
-	    set line [encoding convertfrom $line]
+	    set line [encoding convertfrom utf-8 $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {
@@ -11521,7 +11521,7 @@ proc cache_gitattr {attr pathlist} {
 	    foreach row [split $rlist "\n"] {
 		if {[regexp "(.*): $attr: (.*)" $row m path value]} {
 		    if {[string index $path 0] eq "\""} {
-			set path [encoding convertfrom [lindex $path 0]]
+			set path [encoding convertfrom utf-8 [lindex $path 0]]
 		    }
 		    set path_attr_cache($attr,$path) $value
 		}

From d93346633ff68b26aaf21fb3c5500c9a88a59c08 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:27:53 +0100
Subject: [PATCH 3537/3720] Win32: Unicode arguments (outgoing)

Convert command line arguments from UTF-8 to UTF-16 when creating other
processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index d81e9c02c1..87b5e3bafa 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -955,9 +955,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFO si;
+	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
 	struct strbuf envblk, args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
 	unsigned flags;
 	BOOL ret;
 
@@ -993,6 +994,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	si.hStdOutput = winansi_get_osfhandle(fhout);
 	si.hStdError = winansi_get_osfhandle(fherr);
 
+	if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
 	if (prepend_cmd) {
@@ -1010,6 +1016,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			free(quoted);
 	}
 
+	wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
@@ -1031,12 +1041,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	}
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir, &si, &pi);
+	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
 	if (env)
 		strbuf_release(&envblk);
-	strbuf_release(&args);
+	free(wargs);
 
 	if (!ret) {
 		errno = ENOENT;

From 1f6058a38975a02b948042c1c90f4b13286e8ddf Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:28:27 +0100
Subject: [PATCH 3538/3720] Win32: Unicode arguments (incoming)

Convert command line arguments from UTF-16 to UTF-8 on startup.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 87b5e3bafa..ab5216feb8 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2042,10 +2042,41 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
  */
 int _CRT_glob = 0;
 
+typedef struct {
+	int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+		_startupinfo *si);
+
 void mingw_startup()
 {
-	/* copy executable name to argv[0] */
-	__argv[0] = xstrdup(_pgmptr);
+	int i, len, maxlen, argc;
+	char *buffer;
+	wchar_t **wenv, **wargv;
+	_startupinfo si;
+
+	/* get wide char arguments and environment */
+	si.newmode = 0;
+	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(_wpgmptr);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = xmalloc(maxlen);
+
+	/* convert command line arguments and environment to UTF-8 */
+	len = xwcstoutf(buffer, _wpgmptr, maxlen);
+	__argv[0] = xmemdupz(buffer, len);
+	for (i = 1; i < argc; i++) {
+		len = xwcstoutf(buffer, wargv[i], maxlen);
+		__argv[i] = xmemdupz(buffer, len);
+	}
+	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);

From 1e207b6716fe62e758e2ed9c29dd1c3e9c53f1a4 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:17:49 +0100
Subject: [PATCH 3539/3720] Win32: sync Unicode console output and file system

Use the same Unicode conversion functions for file names and console
conversions so that the file system and console output are in sync when
checking out legacy encoded repositories (i.e. with invalid UTF-8 file
names).

Signed-off-by: Karsten Blees 
---
 compat/winansi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a3e4d88295..9f95954390 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -120,8 +120,7 @@ static void write_console(unsigned char *str, size_t len)
 	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
 
 	/* convert utf-8 to utf-16 */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
-			ARRAY_SIZE(wbuf));
+	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);

From 104ea5f96d87b2f954e1744c1014a04fff30f8cd Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:07:46 +0100
Subject: [PATCH 3540/3720] Win32: Unicode environment (outgoing)

Convert environment from UTF-8 to UTF-16 when creating other processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index ab5216feb8..7e82b519ae 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -957,9 +957,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 {
 	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
-	struct strbuf envblk, args;
-	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
-	unsigned flags;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 
 	/* Determine whether or not we are associated to a console */
@@ -976,7 +976,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * instead of CREATE_NO_WINDOW to make ssh
 		 * recognize that it has no console.
 		 */
-		flags = DETACHED_PROCESS;
+		flags |= DETACHED_PROCESS;
 	} else {
 		/* There is already a console. If we specified
 		 * DETACHED_PROCESS here, too, Windows would
@@ -984,7 +984,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * The same is true for CREATE_NO_WINDOW.
 		 * Go figure!
 		 */
-		flags = 0;
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
@@ -1023,6 +1022,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
+		int size = 0, wenvsz = 0, wenvpos = 0;
 
 		for (e = env; *e; e++)
 			count++;
@@ -1032,20 +1032,22 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
 		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
 
-		strbuf_init(&envblk, 0);
+		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
-			strbuf_addstr(&envblk, *e);
-			strbuf_addch(&envblk, '\0');
+			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
 		}
+		/* add final \0 terminator */
+		wenvblk[wenvpos] = 0;
 		free(sorted_env);
 	}
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
+		wenvblk, dir ? wdir : NULL, &si, &pi);
 
-	if (env)
-		strbuf_release(&envblk);
+	free(wenvblk);
 	free(wargs);
 
 	if (!ret) {

From dbbb8d62419167470e43baab1934c2a7af52f3ee Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 25 Apr 2011 23:32:27 +0100
Subject: [PATCH 3541/3720] Win32: Unicode environment (incoming)

Convert environment from UTF-16 to UTF-8 on startup.

No changes to getenv() are necessary, as the MSVCRT version is implemented
on top of char **environ.

However, putenv / _wputenv from MSVCRT no longer work, for two reasons:
1. they try to keep environ, _wenviron and the Win32 process environment
in sync, using the default system encoding instead of UTF-8 to convert
between charsets
2. msysgit and MSVCRT use different allocators, memory allocated in git
cannot be freed by the CRT and vice versa

Implement mingw_putenv using the env_setenv helper function from the
environment merge code.

Note that in case of memory allocation failure, putenv now dies with error
message (due to xrealloc) instead of failing with ENOMEM. As git assumes
setenv / putenv to always succeed, this prevents it from continuing with
incorrect settings.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 7e82b519ae..727e389025 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1284,6 +1284,12 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -2066,6 +2072,11 @@ void mingw_startup()
 	maxlen = wcslen(_wpgmptr);
 	for (i = 1; i < argc; i++)
 		maxlen = max(maxlen, wcslen(wargv[i]));
+	for (i = 0; wenv[i]; i++)
+		maxlen = max(maxlen, wcslen(wenv[i]));
+
+	/* nedmalloc can't free CRT memory, allocate resizable environment list */
+	environ = xcalloc(i + 1, sizeof(char*));
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2078,6 +2089,10 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wargv[i], maxlen);
 		__argv[i] = xmemdupz(buffer, len);
 	}
+	for (i = 0; wenv[i]; i++) {
+		len = xwcstoutf(buffer, wenv[i], maxlen);
+		environ[i] = xmemdupz(buffer, len);
+	}
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
diff --git a/compat/mingw.h b/compat/mingw.h
index 11928fc835..8b60ee038e 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -201,6 +201,8 @@ char *mingw_getcwd(char *pointer, int len);
 
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
+int mingw_putenv(const char *namevalue);
+#define putenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 91eb00d3a9f907be9478e17644f54415f430ace6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 20 Aug 2011 14:27:02 +0200
Subject: [PATCH 3542/3720] MinGW: disable legacy encoding tests

On Windows, all native APIs are Unicode-based. It is impossible to pass
legacy encoded byte arrays to a process via command line or environment
variables. Disable the tests that try to do so.

In t3901, most tests still work if we don't mess up the repository encoding
in setup, so don't switch to ISO-8859-1 on MinGW.

Note that i18n tests that do their encoding tricks via encoded files (such
as t3900) are not affected by this.

Signed-off-by: Karsten Blees 
---
 t/t3901-i18n-patch.sh | 19 +++++++++++--------
 t/t4201-shortlog.sh   |  6 +++---
 t/t8005-blame-i18n.sh |  8 ++++----
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 31a5770b34..55c8a2f576 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -54,10 +54,13 @@ test_expect_success setup '
 	git add yours &&
 	git commit -s -m "Second on side" &&
 
-	# the second one on the side branch is ISO-8859-1
-	git config i18n.commitencoding ISO8859-1 &&
-	# use author and committer name in ISO-8859-1 to match it.
-	. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+	if test_have_prereq NOT_MINGW
+	then
+		# the second one on the side branch is ISO-8859-1
+		git config i18n.commitencoding ISO8859-1 &&
+		# use author and committer name in ISO-8859-1 to match it.
+		. "$TEST_DIRECTORY"/t3901-8859-1.txt
+	fi &&
 	test_tick &&
 	echo Yet another >theirs &&
 	git add theirs &&
@@ -119,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
 	check_encoding 2
 '
 
-test_expect_success 'rebase (L/L)' '
+test_expect_success NOT_MINGW 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
 	git config i18n.commitencoding ISO8859-1 &&
 	git config i18n.logoutputencoding ISO8859-1 &&
@@ -131,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 	check_encoding 2 8859
 '
 
-test_expect_success 'rebase (L/U)' '
+test_expect_success NOT_MINGW 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
 	git config i18n.commitencoding ISO8859-1 &&
@@ -159,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/L)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
 	git config i18n.commitencoding ISO8859-1 &&
@@ -189,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/U)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6872ba1a42..48963811bf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
 	test_cmp expect log.predictable
 '
 
-test_expect_success 'shortlog wrapping' '
+test_expect_success NOT_MINGW 'shortlog wrapping' '
 	cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
 	test_cmp expect out
 '
 
-test_expect_success 'shortlog from non-git directory' '
+test_expect_success NOT_MINGW 'shortlog from non-git directory' '
 	git log HEAD >log &&
 	GIT_DIR=non-existing git shortlog -w out &&
 	test_cmp expect out
@@ -135,7 +135,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success 'shortlog encoding' '
+test_expect_success NOT_MINGW 'shortlog encoding' '
 	git reset --hard "$commit" &&
 	git config --unset i18n.commitencoding &&
 	echo 2 > a1 &&
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index cb390559f9..a6e73d0635 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.commitencoding' '
 	git blame --incremental file | \
 		egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.logoutputencoding' '
 	git config i18n.logoutputencoding eucJP &&
 	git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=UTF-8' '
 	git blame --incremental --encoding=UTF-8 file | \
 		egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=none' '
 	git blame --incremental --encoding=none file | \
 		egrep "^(author|summary) " > actual &&

From 8cb05bdbe4be52e36426e7de0ed7b661c081950c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:29:40 +0100
Subject: [PATCH 3543/3720] Win32: fix environment memory leaks

All functions that modify the environment have memory leaks.

Disable gitunsetenv in the Makefile and use env_setenv (via mingw_putenv)
instead (this frees removed environment entries).

Move xstrdup from env_setenv to make_augmented_environ, so that
mingw_putenv no longer copies the environment entries (according to POSIX
[1], "the string [...] shall become part of the environment"). This also
fixes the memory leak in gitsetenv, which expects a POSIX compliant putenv.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html

Note: This patch depends on taking control of char **environ and having
our own mingw_putenv (both introduced in "Win32: Unicode environment
(incoming)").

Signed-off-by: Karsten Blees 
---
 Makefile       |  2 --
 compat/mingw.c | 10 ++++++----
 compat/mingw.h |  1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 5ac4f5403d..2b709e900e 100644
--- a/Makefile
+++ b/Makefile
@@ -1208,7 +1208,6 @@ ifeq ($(uname_S),Windows)
 	NO_IPV6 = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
@@ -1305,7 +1304,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SYMLINK_HEAD = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index 727e389025..3dfa95a473 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1257,14 +1257,14 @@ static char **env_setenv(char **env, const char *name)
 			for (i = 0; env[i]; i++)
 				;
 			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 			env[i+1] = NULL;
 		}
 	}
 	else {
 		free(env[i]);
 		if (*eq)
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 		else
 			for (; env[i]; i++)
 				env[i] = env[i+1];
@@ -1279,8 +1279,10 @@ char **make_augmented_environ(const char *const *vars)
 {
 	char **env = copy_environ();
 
-	while (*vars)
-		env = env_setenv(env, *vars++);
+	while (*vars) {
+		const char *v = *vars++;
+		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+	}
 	return env;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index 8b60ee038e..edb1653c50 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -203,6 +203,7 @@ char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 int mingw_putenv(const char *namevalue);
 #define putenv mingw_putenv
+#define unsetenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From caf23f91f36bd91f1d9a37322c91c4888ed06194 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 23:42:09 +0100
Subject: [PATCH 3544/3720] Win32: unify environment case-sensitivity

The environment on Windows is case-insensitive. Some environment functions
(such as unsetenv and make_augmented_environ) have always used case-
sensitive comparisons instead, while others (getenv, putenv, sorting in
spawn*) were case-insensitive.

Prevent potential inconsistencies by using case-insensitive comparison in
lookup_env (used by putenv, unsetenv and make_augmented_environ).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 3dfa95a473..4e514e1924 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1236,8 +1236,7 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 	int i;
 
 	for (i = 0; env[i]; i++) {
-		if (0 == strncmp(env[i], name, nmln)
-		    && '=' == env[i][nmln])
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
 			/* matches */
 			return i;
 	}

From 8e68fb9383a5ebd8ea45ba8c99492c586cb505ad Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:33:17 +0100
Subject: [PATCH 3545/3720] Win32: simplify internal mingw_spawn* APIs

The only public spawn function that needs to tweak the environment is
mingw_spawnvpe (called from start_command). Nevertheless, all internal
spawn* functions take an env parameter and needlessly pass the global
char **environ around. Remove the env parameter where it's not needed.

This removes the internal mingw_execve abstraction, which is no longer
needed.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 4e514e1924..dcfe4969d3 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1077,10 +1077,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-			   int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -1122,7 +1121,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 	return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
 	const char *interpr = parse_interpreter(cmd);
 	char **path;
@@ -1140,7 +1139,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 		argv2 = xmalloc(sizeof(*argv) * (argc+1));
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-		pid = mingw_spawnve(prog, argv2, env, 1);
+		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -1155,13 +1154,13 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 	return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+void mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
-	if (!try_shell_exec(cmd, argv, (char **)env)) {
+	if (!try_shell_exec(cmd, argv)) {
 		int pid, status;
 
-		pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
 			return;
 		if (waitpid(pid, &status, 0) < 0)
@@ -1176,7 +1175,7 @@ int mingw_execvp(const char *cmd, char *const *argv)
 	char *prog = path_lookup(cmd, path, 0);
 
 	if (prog) {
-		mingw_execve(prog, argv, environ);
+		mingw_execv(prog, argv);
 		free(prog);
 	} else
 		errno = ENOENT;
@@ -1185,12 +1184,6 @@ int mingw_execvp(const char *cmd, char *const *argv)
 	return -1;
 }
 
-int mingw_execv(const char *cmd, char *const *argv)
-{
-	mingw_execve(cmd, argv, environ);
-	return -1;
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
 	if (pid > 0 && sig == SIGTERM) {

From 6ccd2ac92b8ca00d1b7c6319f504f63f00ea28e5 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:05:04 +0100
Subject: [PATCH 3546/3720] Win32: move environment functions

Move environment helper functions up so that they can be reused by
mingw_getenv and mingw_spawnve_fd in subsequent patches.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 106 ++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index dcfe4969d3..bb0f3f5bed 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,6 +737,53 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
+static int env_compare(const void *a, const void *b)
+{
+	char *const *ea = a;
+	char *const *eb = b;
+	return strcasecmp(*ea, *eb);
+}
+
+static int lookup_env(char **env, const char *name, size_t nmln)
+{
+	int i;
+
+	for (i = 0; env[i]; i++) {
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
+			/* matches */
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * If name contains '=', then sets the variable, otherwise it unsets it
+ */
+static char **env_setenv(char **env, const char *name)
+{
+	char *eq = strchrnul(name, '=');
+	int i = lookup_env(env, name, eq-name);
+
+	if (i < 0) {
+		if (*eq) {
+			for (i = 0; env[i]; i++)
+				;
+			env = xrealloc(env, (i+2)*sizeof(*env));
+			env[i] = (char*) name;
+			env[i+1] = NULL;
+		}
+	}
+	else {
+		free(env[i]);
+		if (*eq)
+			env[i] = (char*) name;
+		else
+			for (; env[i]; i++)
+				env[i] = env[i+1];
+	}
+	return env;
+}
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -754,6 +801,12 @@ char *mingw_getenv(const char *name)
 	return result;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -936,13 +989,6 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
-static int env_compare(const void *a, const void *b)
-{
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
-}
-
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1224,46 +1270,6 @@ void free_environ(char **env)
 	free(env);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
-{
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
-	}
-	return -1;
-}
-
-/*
- * If name contains '=', then sets the variable, otherwise it unsets it
- */
-static char **env_setenv(char **env, const char *name)
-{
-	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
-
-	if (i < 0) {
-		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
-		}
-	}
-	else {
-		free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-	}
-	return env;
-}
-
 /*
  * Copies global environ and adjusts variables as specified by vars.
  */
@@ -1278,12 +1284,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-int mingw_putenv(const char *namevalue)
-{
-	environ = env_setenv(environ, namevalue);
-	return 0;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 96e1394fe505c5f9b309a0e46ba026a8f45e714a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Wed, 5 Oct 2011 22:01:46 +0200
Subject: [PATCH 3547/3720] Win32: unify environment function names

Environment helper functions use random naming ('env' prefix or suffix or
both, with or without '_'). Change to POSIX naming scheme ('env' suffix,
no '_').

Env_setenv has more in common with putenv than setenv. Change to do_putenv.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bb0f3f5bed..ceeca910d8 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,14 +737,14 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int env_compare(const void *a, const void *b)
+static int compareenv(const void *a, const void *b)
 {
 	char *const *ea = a;
 	char *const *eb = b;
 	return strcasecmp(*ea, *eb);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
+static int lookupenv(char **env, const char *name, size_t nmln)
 {
 	int i;
 
@@ -759,10 +759,10 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **env_setenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name)
 {
 	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
+	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
@@ -803,7 +803,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = env_setenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue);
 	return 0;
 }
 
@@ -1076,7 +1076,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		/* environment must be sorted */
 		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
 
 		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
@@ -1279,7 +1279,7 @@ char **make_augmented_environ(const char *const *vars)
 
 	while (*vars) {
 		const char *v = *vars++;
-		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
 	}
 	return env;
 }

From 854e1b2506476c01572525e202629944bff75f55 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:31:57 +0100
Subject: [PATCH 3548/3720] Win32: factor out environment block creation

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 55 +++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index ceeca910d8..4d24ca06b6 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -989,6 +989,36 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
+/*
+ * Create environment block suitable for CreateProcess.
+ */
+static wchar_t *make_environment_block(char **env)
+{
+	wchar_t *wenvblk = NULL;
+	int count = 0;
+	char **e, **tmpenv;
+	int size = 0, wenvsz = 0, wenvpos = 0;
+
+	for (e = env; *e; e++)
+		count++;
+
+	/* environment must be sorted */
+	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+
+	/* create environment block from temporary environment */
+	for (e = tmpenv; *e; e++) {
+		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+	}
+	/* add final \0 terminator */
+	wenvblk[wenvpos] = 0;
+	free(tmpenv);
+	return wenvblk;
+}
+
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1065,29 +1095,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env) {
-		int count = 0;
-		char **e, **sorted_env;
-		int size = 0, wenvsz = 0, wenvpos = 0;
-
-		for (e = env; *e; e++)
-			count++;
-
-		/* environment must be sorted */
-		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
-		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
-
-		/* create environment block from temporary environment */
-		for (e = sorted_env; *e; e++) {
-			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
-			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
-		}
-		/* add final \0 terminator */
-		wenvblk[wenvpos] = 0;
-		free(sorted_env);
-	}
+	if (env)
+		wenvblk = make_environment_block(env);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,

From ceeb426742e23c8b521d51f5c3564d35c8957526 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:57:14 +0100
Subject: [PATCH 3549/3720] Win32: don't copy the environment twice when
 spawning child processes

When spawning child processes via start_command(), the environment and all
environment entries are copied twice. First by make_augmented_environ /
copy_environ to merge with child_process.env. Then a second time by
make_environment_block to create a sorted environment block string as
required by CreateProcess.

Move the merge logic to make_environment_block so that we only need to copy
the environment once. This changes semantics of the env parameter: it now
expects a delta (such as child_process.env) rather than a full environment.
This is not a problem as the parameter is only used by start_command()
(all other callers previously passed char **environ, and now pass NULL).

The merge logic no longer xstrdup()s the environment strings, so do_putenv
must not free them. Add a parameter to distinguish this from normal putenv.

Remove the now unused make_augmented_environ / free_environ API.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 74 ++++++++++++++++----------------------------------
 compat/mingw.h |  6 ----
 run-command.c  | 10 ++-----
 3 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 4d24ca06b6..9ed3f82d33 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -759,7 +759,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **do_putenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
@@ -774,7 +774,8 @@ static char **do_putenv(char **env, const char *name)
 		}
 	}
 	else {
-		free(env[i]);
+		if (free_old)
+			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
 		else
@@ -803,7 +804,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue, 1);
 	return 0;
 }
 
@@ -990,21 +991,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 }
 
 /*
- * Create environment block suitable for CreateProcess.
+ * Create environment block suitable for CreateProcess. Merges current
+ * process environment and the supplied environment changes.
  */
-static wchar_t *make_environment_block(char **env)
+static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
 	int count = 0;
 	char **e, **tmpenv;
 	int size = 0, wenvsz = 0, wenvpos = 0;
 
-	for (e = env; *e; e++)
+	while (environ[count])
 		count++;
 
-	/* environment must be sorted */
+	/* copy the environment */
 	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+
+	/* merge supplied environment changes into the temporary environment */
+	for (e = deltaenv; e && *e; e++)
+		tmpenv = do_putenv(tmpenv, *e, 0);
+
+	/* environment must be sorted */
+	for (count = 0; tmpenv[count]; )
+		count++;
 	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
 
 	/* create environment block from temporary environment */
@@ -1027,7 +1037,7 @@ struct pinfo_t {
 struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
-static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
@@ -1095,8 +1105,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env)
-		wenvblk = make_environment_block(env);
+	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1134,10 +1143,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
 static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 		     const char *dir,
 		     int fhin, int fhout, int fherr)
 {
@@ -1161,14 +1170,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 				pid = -1;
 			}
 			else {
-				pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
 						       fhin, fhout, fherr);
 				free(iprog);
 			}
 			argv[0] = argv0;
 		}
 		else
-			pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
 					       fhin, fhout, fherr);
 		free(prog);
 	}
@@ -1258,41 +1267,6 @@ int mingw_kill(pid_t pid, int sig)
 	return -1;
 }
 
-static char **copy_environ(void)
-{
-	char **env;
-	int i = 0;
-	while (environ[i])
-		i++;
-	env = xmalloc((i+1)*sizeof(*env));
-	for (i = 0; environ[i]; i++)
-		env[i] = xstrdup(environ[i]);
-	env[i] = NULL;
-	return env;
-}
-
-void free_environ(char **env)
-{
-	int i;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-/*
- * Copies global environ and adjusts variables as specified by vars.
- */
-char **make_augmented_environ(const char *const *vars)
-{
-	char **env = copy_environ();
-
-	while (*vars) {
-		const char *v = *vars++;
-		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
-	}
-	return env;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
diff --git a/compat/mingw.h b/compat/mingw.h
index edb1653c50..45f5569e53 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -336,12 +336,6 @@ void mingw_open_html(const char *path);
 void mingw_mark_as_git_dir(const char *dir);
 #define mark_as_git_dir mingw_mark_as_git_dir
 
-/*
- * helpers
- */
-
-char **make_augmented_environ(const char *const *vars);
-void free_environ(char **env);
 
 /**
  * Converts UTF-8 encoded string to UTF-16LE.
diff --git a/run-command.c b/run-command.c
index 606791dc67..e665368469 100644
--- a/run-command.c
+++ b/run-command.c
@@ -451,7 +451,6 @@ fail_pipe:
 {
 	int fhin = 0, fhout = 1, fherr = 2;
 	const char **sargv = cmd->argv;
-	char **env = environ;
 
 	if (cmd->no_stdin)
 		fhin = open("/dev/null", O_RDWR);
@@ -476,25 +475,20 @@ fail_pipe:
 	else if (cmd->out > 1)
 		fhout = dup(cmd->out);
 
-	if (cmd->env)
-		env = make_augmented_environ(cmd->env);
-
 	if (cmd->git_cmd) {
 		cmd->argv = prepare_git_cmd(cmd->argv);
 	} else if (cmd->use_shell) {
 		cmd->argv = prepare_shell_cmd(cmd->argv);
 	}
 
-	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
-				  fhin, fhout, fherr);
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
 	failed_errno = errno;
 	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 		error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 	if (cmd->clean_on_exit && cmd->pid >= 0)
 		mark_child_for_cleanup(cmd->pid);
 
-	if (cmd->env)
-		free_environ(env);
 	if (cmd->git_cmd)
 		free(cmd->argv);
 

From 28158f8d18ef0add1356db1152660a6387658d7f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:00:35 +0100
Subject: [PATCH 3550/3720] Win32: reduce environment array reallocations

Move environment array reallocation from do_putenv to the respective
callers. Keep track of the environment size in a global variable. Use
ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a
sufficiently sized environment array in make_environment_block to prevent
reallocations.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 60 ++++++++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9ed3f82d33..dcd5c4139b 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -758,19 +758,19 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
+ * Size includes the terminating NULL. Env must have room for size + 1 entries
+ * (in case of insert). Returns the new size. Optionally frees removed entries.
  */
-static char **do_putenv(char **env, const char *name, int free_old)
+static int do_putenv(char **env, const char *name, int size, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
+			env[size - 1] = (char*) name;
+			env[size] = NULL;
+			size++;
 		}
 	}
 	else {
@@ -778,13 +778,20 @@ static char **do_putenv(char **env, const char *name, int free_old)
 			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
-		else
+		else {
 			for (; env[i]; i++)
 				env[i] = env[i+1];
+			size--;
+		}
 	}
-	return env;
+	return size;
 }
 
+/* used number of elements of environ array, including terminating NULL */
+static int environ_size = 0;
+/* allocated size of environ array, in bytes */
+static int environ_alloc = 0;
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -804,7 +811,8 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue, 1);
+	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
+	environ_size = do_putenv(environ, namevalue, environ_size, 1);
 	return 0;
 }
 
@@ -997,31 +1005,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
-	int count = 0;
-	char **e, **tmpenv;
-	int size = 0, wenvsz = 0, wenvpos = 0;
+	char **tmpenv;
+	int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
 
-	while (environ[count])
-		count++;
+	while (deltaenv && deltaenv[i])
+		i++;
 
-	/* copy the environment */
-	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+	/* copy the environment, leaving space for changes */
+	tmpenv = xmalloc((size + i) * sizeof(char*));
+	memcpy(tmpenv, environ, size * sizeof(char*));
 
 	/* merge supplied environment changes into the temporary environment */
-	for (e = deltaenv; e && *e; e++)
-		tmpenv = do_putenv(tmpenv, *e, 0);
+	for (i = 0; deltaenv && deltaenv[i]; i++)
+		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
 	/* environment must be sorted */
-	for (count = 0; tmpenv[count]; )
-		count++;
-	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
 
 	/* create environment block from temporary environment */
-	for (e = tmpenv; *e; e++) {
-		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+	for (i = 0; tmpenv[i]; i++) {
+		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
 		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+		wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
 	}
 	/* add final \0 terminator */
 	wenvblk[wenvpos] = 0;
@@ -2053,7 +2058,9 @@ void mingw_startup()
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
 	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = xcalloc(i + 1, sizeof(char*));
+	environ = NULL;
+	environ_size = i + 1;
+	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2070,6 +2077,7 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wenv[i], maxlen);
 		environ[i] = xmemdupz(buffer, len);
 	}
+	environ[i] = NULL;
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */

From cf4b5cb5fff31c3a48605358aaab603fb934effa Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:29:04 +0100
Subject: [PATCH 3551/3720] Win32: use low-level memory allocation during
 initialization

As of d41489a6 "Add more large blob test cases", git's high-level memory
allocation functions (xmalloc, xmemdupz etc.) access the environment to
simulate limited memory in tests (see 'getenv("GIT_ALLOC_LIMIT")' in
memory_limit_check()). These functions should not be used before the
environment is fully initialized (particularly not to initialize the
environment itself).

The current solution ('environ = NULL; ALLOC_GROW(environ...)') only works
because MSVCRT's getenv() reinitializes environ when it is NULL (i.e. it
leaves us with two sets of unusabe (non-UTF-8) and unfreeable (CRT-
allocated) environments).

Add our own set of malloc-or-die functions to be used in startup code.

Also check the result of __wgetmainargs, which may fail if there's not
enough memory for wide-char arguments and environment.

This patch is in preparation of the sorted environment feature, which
completely replaces MSVCRT's getenv() implementation.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 52 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index dcd5c4139b..ad5f87527f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2039,16 +2039,37 @@ typedef struct {
 extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
 		_startupinfo *si);
 
+static NORETURN void die_startup()
+{
+	fputs("fatal: not enough memory for initialization", stderr);
+	exit(128);
+}
+
+static void *malloc_startup(size_t size)
+{
+	void *result = malloc(size);
+	if (!result)
+		die_startup();
+	return result;
+}
+
+static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
+{
+	len = xwcstoutf(buffer, wcs, len) + 1;
+	return memcpy(malloc_startup(len), buffer, len);
+}
+
 void mingw_startup()
 {
-	int i, len, maxlen, argc;
+	int i, maxlen, argc;
 	char *buffer;
 	wchar_t **wenv, **wargv;
 	_startupinfo si;
 
 	/* get wide char arguments and environment */
 	si.newmode = 0;
-	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+	if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
+		die_startup();
 
 	/* determine size of argv and environ conversion buffer */
 	maxlen = wcslen(_wpgmptr);
@@ -2057,26 +2078,25 @@ void mingw_startup()
 	for (i = 0; wenv[i]; i++)
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
-	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = NULL;
+	/*
+	 * nedmalloc can't free CRT memory, allocate resizable environment
+	 * list. Note that xmalloc / xmemdupz etc. call getenv, so we cannot
+	 * use it while initializing the environment itself.
+	 */
 	environ_size = i + 1;
-	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
+	environ_alloc = alloc_nr(environ_size * sizeof(char*));
+	environ = malloc_startup(environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
-	buffer = xmalloc(maxlen);
+	buffer = malloc_startup(maxlen);
 
 	/* convert command line arguments and environment to UTF-8 */
-	len = xwcstoutf(buffer, _wpgmptr, maxlen);
-	__argv[0] = xmemdupz(buffer, len);
-	for (i = 1; i < argc; i++) {
-		len = xwcstoutf(buffer, wargv[i], maxlen);
-		__argv[i] = xmemdupz(buffer, len);
-	}
-	for (i = 0; wenv[i]; i++) {
-		len = xwcstoutf(buffer, wenv[i], maxlen);
-		environ[i] = xmemdupz(buffer, len);
-	}
+	__argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
+	for (i = 1; i < argc; i++)
+		__argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+	for (i = 0; wenv[i]; i++)
+		environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen);
 	environ[i] = NULL;
 	free(buffer);
 

From fef121c10c29aec1e420ceb4ab99f46660118a25 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:30:02 +0100
Subject: [PATCH 3552/3720] Win32: keep the environment sorted

The Windows environment is sorted, keep it that way for O(log n)
environment access.

Change compareenv to compare only the keys, so that it can be used to
find an entry irrespective of the value.

Change lookupenv to binary seach for an entry. Return one's complement of
the insert position if not found (libc's bsearch returns NULL).

Replace MSVCRT's getenv with a minimal do_getenv based on the binary search
function.

Change do_putenv to insert new entries at the correct position. Simplify
the function by swapping if conditions and using memmove instead of for
loops.

Move qsort from make_environment_block to mingw_startup. We still need to
sort on startup to make sure that the environment is sorted according to
our compareenv function (while Win32 / CreateProcess requires the
environment block to be sorted case-insensitively, CreateProcess currently
doesn't enforce this, and some applications such as bash just don't care).

Note that environment functions are _not_ thread-safe and are not required
to be so by POSIX, the application is responsible for synchronizing access
to the environment. MSVCRT's getenv and our new getenv implementation are
better than that in that they are thread-safe with respect to other getenv
calls as long as the environment is not modified. Git's indiscriminate use
of getenv in background threads currently requires this property.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 98 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 62 insertions(+), 36 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index ad5f87527f..9afba8d4f8 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,23 +737,42 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int compareenv(const void *a, const void *b)
+/*
+ * Compare environment entries by key (i.e. stopping at '=' or '\0').
+ */
+static int compareenv(const void *v1, const void *v2)
 {
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
+	const char *e1 = *(const char**)v1;
+	const char *e2 = *(const char**)v2;
+
+	for (;;) {
+		int c1 = *e1++;
+		int c2 = *e2++;
+		c1 = (c1 == '=') ? 0 : tolower(c1);
+		c2 = (c2 == '=') ? 0 : tolower(c2);
+		if (c1 > c2)
+			return 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 == 0)
+			return 0;
+	}
 }
 
-static int lookupenv(char **env, const char *name, size_t nmln)
+static int bsearchenv(char **env, const char *name, size_t size)
 {
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
+	unsigned low = 0, high = size;
+	while (low < high) {
+		unsigned mid = low + ((high - low) >> 1);
+		int cmp = compareenv(&env[mid], &name);
+		if (cmp < 0)
+			low = mid + 1;
+		else if (cmp > 0)
+			high = mid;
+		else
+			return mid;
 	}
-	return -1;
+	return ~low; /* not found, return 1's complement of insert position */
 }
 
 /*
@@ -763,26 +782,24 @@ static int lookupenv(char **env, const char *name, size_t nmln)
  */
 static int do_putenv(char **env, const char *name, int size, int free_old)
 {
-	char *eq = strchrnul(name, '=');
-	int i = lookupenv(env, name, eq-name);
+	int i = bsearchenv(env, name, size - 1);
 
-	if (i < 0) {
-		if (*eq) {
-			env[size - 1] = (char*) name;
-			env[size] = NULL;
+	/* optionally free removed / replaced entry */
+	if (i >= 0 && free_old)
+		free(env[i]);
+
+	if (strchr(name, '=')) {
+		/* if new value ('key=value') is specified, insert or replace entry */
+		if (i < 0) {
+			i = ~i;
+			memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
 			size++;
 		}
-	}
-	else {
-		if (free_old)
-			free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else {
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-			size--;
-		}
+		env[i] = (char*) name;
+	} else if (i >= 0) {
+		/* otherwise ('key') remove existing entry */
+		size--;
+		memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
 	}
 	return size;
 }
@@ -792,15 +809,24 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-#undef getenv
+static char *do_getenv(const char *name)
+{
+	char *value;
+	int pos = bsearchenv(environ, name, environ_size - 1);
+	if (pos < 0)
+		return NULL;
+	value = strchr(environ[pos], '=');
+	return value ? &value[1] : NULL;
+}
+
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv(name);
+	char *result = do_getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
+		result = do_getenv("TMP");
 		if (!result)
-			result = getenv("TEMP");
+			result = do_getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */
@@ -1019,9 +1045,6 @@ static wchar_t *make_environment_block(char **deltaenv)
 	for (i = 0; deltaenv && deltaenv[i]; i++)
 		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
-	/* environment must be sorted */
-	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
-
 	/* create environment block from temporary environment */
 	for (i = 0; tmpenv[i]; i++) {
 		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
@@ -2100,6 +2123,9 @@ void mingw_startup()
 	environ[i] = NULL;
 	free(buffer);
 
+	/* sort environment for O(log n) getenv / putenv */
+	qsort(environ, i, sizeof(char*), compareenv);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 903026254fa4f1547ae274f36b3220df7c671321 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:35:26 +0100
Subject: [PATCH 3553/3720] Win32: patch Windows environment on startup

Fix Windows specific environment settings on startup rather than checking
for special values on every getenv call.

As a side effect, this makes the patched environment (i.e. with properly
initialized TMPDIR and TERM) available to child processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9afba8d4f8..d0ae52c2b4 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -809,7 +809,7 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-static char *do_getenv(const char *name)
+char *mingw_getenv(const char *name)
 {
 	char *value;
 	int pos = bsearchenv(environ, name, environ_size - 1);
@@ -819,22 +819,6 @@ static char *do_getenv(const char *name)
 	return value ? &value[1] : NULL;
 }
 
-char *mingw_getenv(const char *name)
-{
-	char *result = do_getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = do_getenv("TMP");
-		if (!result)
-			result = do_getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 int mingw_putenv(const char *namevalue)
 {
 	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
@@ -2126,6 +2110,21 @@ void mingw_startup()
 	/* sort environment for O(log n) getenv / putenv */
 	qsort(environ, i, sizeof(char*), compareenv);
 
+	/* fix Windows specific environment settings */
+
+	/* on Windows it is TMP and TEMP */
+	if (!getenv("TMPDIR")) {
+		const char *tmp = getenv("TMP");
+		if (!tmp)
+			tmp = getenv("TEMP");
+		if (tmp)
+			setenv("TMPDIR", tmp, 1);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "winansi", 1);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From b0f97c3874ed2881b51e49ccd9dbbcf521e0cb63 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:37:26 +0100
Subject: [PATCH 3554/3720] Win32: fix detection of empty directories in
 is_dir_empty

On Windows XP (not Win7), directories cannot be deleted while a find handle
is open, causing "Deletion of directory '...' failed. Should I try again?"
prompts.

Prior to 19d1e75d "Win32: Unicode file name support (except dirent)",
these failures were silently ignored due to strbuf_free in is_dir_empty
resetting GetLastError to ERROR_SUCCESS.

Close the find handle in is_dir_empty so that git doesn't block deletion
of the directory even after all other applications have released it.

Reported-by: John Chen 
Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index d0ae52c2b4..86c3fe7bdc 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -243,8 +243,11 @@ static int is_dir_empty(const wchar_t *wpath)
 
 	while (!wcscmp(findbuf.cFileName, L".") ||
 			!wcscmp(findbuf.cFileName, L".."))
-		if (!FindNextFileW(handle, &findbuf))
-			return GetLastError() == ERROR_NO_MORE_FILES;
+		if (!FindNextFileW(handle, &findbuf)) {
+			DWORD err = GetLastError();
+			FindClose(handle);
+			return err == ERROR_NO_MORE_FILES;
+		}
 	FindClose(handle);
 	return 0;
 }

From ebe5cc9d04e20d4313ab14337d91b0651eb74372 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Fri, 23 Mar 2012 10:58:37 +0100
Subject: [PATCH 3555/3720] am: Use cat instead of echo to avoid DOS
 line-endings (fixes t4150)

Along the lines of 05d0e3b and f33946d, use cat instead of echo to avoid
line ending mismatches in the test result of "am empty-file does not
infloop" which make the test fail.

Signed-off-by: Sebastian Schuberth 
---
 git-am.sh | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/git-am.sh b/git-am.sh
index 11ca959c3f..c2f787c1f7 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -183,7 +183,9 @@ It does not apply to blobs recorded in its index.")"
 }
 
 clean_abort () {
-	test $# = 0 || echo >&2 "$@"
+	test $# = 0 || cat >&2 <
Date: Sun, 24 Jul 2011 15:54:04 +0200
Subject: [PATCH 3556/3720] t9350: point out that refs are not updated
 correctly

This happens only when the corresponding commits are not exported in
the current fast-export run. This can happen either when the relevant
commit is already marked, or when the commit is explicitly marked
as UNINTERESTING with a negative ref by another argument.

This breaks fast-export basec remote helpers.

Signed-off-by: Sverre Rabbelier 
---
 t/t9350-fast-export.sh | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index b00196bd23..57569a7eed 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -440,4 +440,15 @@ test_expect_success 'fast-export quotes pathnames' '
 	)
 '
 
+cat > expected << EOF
+reset refs/heads/master
+from $(git rev-parse master)
+
+EOF
+
+test_expect_failure 'refs are updated even if no commits need to be exported' '
+	git fast-export master..master > actual &&
+	test_cmp expected actual
+'
+
 test_done

From ce357ce2da5b12d1b9ef8a7ea10ef275ec48958e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 15:55:26 +0200
Subject: [PATCH 3557/3720] fast-export: do not refer to non-existing marks

When calling `git fast-export a..a b` when a and b refer to the same
commit, nothing would be exported, and an incorrect reset line would
be printed for b ('from :0').

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 19509ea754..b0891b3735 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -529,9 +529,20 @@ static void get_tags_and_duplicates(struct object_array *pending,
 	}
 }
 
+static void handle_reset(const char *name, struct object *object)
+{
+	int mark = get_object_mark(object);
+
+	if (mark)
+		printf("reset %s\nfrom :%d\n\n", name,
+		       get_object_mark(object));
+	else
+		printf("reset %s\nfrom %s\n\n", name,
+		       sha1_to_hex(object->sha1));
+}
+
 static void handle_tags_and_duplicates(struct string_list *extra_refs)
 {
-	struct commit *commit;
 	int i;
 
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
@@ -543,9 +554,7 @@ static void handle_tags_and_duplicates(struct string_list *extra_refs)
 			break;
 		case OBJ_COMMIT:
 			/* create refs pointing to already seen commits */
-			commit = (struct commit *)object;
-			printf("reset %s\nfrom :%d\n\n", name,
-			       get_object_mark(&commit->object));
+			handle_reset(name, object);
 			show_progress();
 			break;
 		}

From 88374204fa8c5e1fe8ca14b4fb60fde5e2f92c39 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 17:14:47 +0200
Subject: [PATCH 3558/3720] setup_revisions: remember whether a ref was
 positive or not

This will be required by fast-export, when no commits were
exported, but the refs should be set, of course.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 object.h   |  2 +-
 revision.c | 12 +++++++-----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/object.h b/object.h
index 6a97b6ba1a..0001752c6d 100644
--- a/object.h
+++ b/object.h
@@ -12,7 +12,7 @@ struct object_array {
 	struct object_array_entry {
 		struct object *item;
 		const char *name;
-		unsigned mode;
+		unsigned mode, flags;
 	} *objects;
 };
 
diff --git a/revision.c b/revision.c
index 935e7a7ba4..206a5b69fe 100644
--- a/revision.c
+++ b/revision.c
@@ -185,7 +185,7 @@ void mark_parents_uninteresting(struct commit *commit)
 	}
 }
 
-static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
+static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode, unsigned flags)
 {
 	if (!obj)
 		return;
@@ -206,11 +206,12 @@ static void add_pending_object_with_mode(struct rev_info *revs, struct object *o
 			return;
 	}
 	add_object_array_with_mode(obj, name, &revs->pending, mode);
+	revs->pending.objects[revs->pending.nr-1].flags = flags;
 }
 
 void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
 {
-	add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
+	add_pending_object_with_mode(revs, obj, name, S_IFINVALID, 0);
 }
 
 void add_head_to_pending(struct rev_info *revs)
@@ -1176,7 +1177,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
 					REV_CMD_LEFT, a_flags);
 			add_rev_cmdline(revs, &b->object, next,
 					REV_CMD_RIGHT, flags);
-			add_pending_object(revs, &a->object, this);
+			add_pending_object_with_mode(revs, &a->object, this,
+						     S_IFINVALID, flags_exclude);
 			add_pending_object(revs, &b->object, next);
 			return 0;
 		}
@@ -1207,7 +1209,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
 		verify_non_filename(revs->prefix, arg);
 	object = get_reference(revs, arg, sha1, flags ^ local_flags);
 	add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
-	add_pending_object_with_mode(revs, object, arg, mode);
+	add_pending_object_with_mode(revs, object, arg, mode, local_flags);
 	return 0;
 }
 
@@ -1824,7 +1826,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 		if (get_sha1_with_mode(revs->def, sha1, &mode))
 			die("bad default revision '%s'", revs->def);
 		object = get_reference(revs, revs->def, sha1, 0);
-		add_pending_object_with_mode(revs, object, revs->def, mode);
+		add_pending_object_with_mode(revs, object, revs->def, mode, 0);
 	}
 
 	/* Did the user ask for any diff output? Run the diff! */

From 892833303db80da9166d468655886db256f13685 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 15:40:23 +0200
Subject: [PATCH 3559/3720] fast-export: do not export negative refs

When calling `git fast-export master..next` we want to export
refs/heads/next, but not refs/heads/master.

Currently this is not a problem, because negative refs' commits
are never shown. In the next commit this will be changed in order
to make sure that 'master..master' does export master. I.e. even
refs whose commits are not shown are exported.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index b0891b3735..0dc5124675 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -484,7 +484,7 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		struct commit *commit = commit;
 		char *full_name;
 
-		if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
+		if ((e->flags & UNINTERESTING) || dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
 			continue;
 
 		switch (e->item->type) {

From 3c7b4365a23cb6a7a308f3bd534e4e4c3a60555f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 17:14:47 +0200
Subject: [PATCH 3560/3720] setup_revisions: remember whether a ref was
 positive or not

This will be required by fast-export, when no commits were
exported, but the refs should be set, of course.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c  | 36 +++++++++++++++++++++++++++++++-----
 t/t9350-fast-export.sh |  2 +-
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 0dc5124675..137792d49d 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -18,6 +18,8 @@
 #include "parse-options.h"
 #include "quote.h"
 
+#define REF_HANDLED (ALL_REV_FLAGS + 1)
+
 static const char *fast_export_usage[] = {
 	"git fast-export [rev-list-opts]",
 	NULL
@@ -473,6 +475,7 @@ static void handle_tag(const char *name, struct tag *tag)
 }
 
 static void get_tags_and_duplicates(struct object_array *pending,
+				    struct string_list *refs,
 				    struct string_list *extra_refs)
 {
 	struct tag *tag;
@@ -524,8 +527,11 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		if (commit->util)
 			/* more than one name for the same object */
 			string_list_append(extra_refs, full_name)->util = commit;
-		else
+		else {
 			commit->util = full_name;
+			/* we might need to set this ref explicitly */
+			string_list_append(refs, full_name)->util = commit;
+		}
 	}
 }
 
@@ -541,10 +547,29 @@ static void handle_reset(const char *name, struct object *object)
 		       sha1_to_hex(object->sha1));
 }
 
-static void handle_tags_and_duplicates(struct string_list *extra_refs)
+static void handle_tags_and_duplicates(struct string_list *refs, struct string_list *extra_refs)
 {
 	int i;
 
+	/* even if no commits were exported, we need to export the ref */
+	for (i = refs->nr - 1; i >= 0; i--) {
+		const char *name = refs->items[i].string;
+		struct object *object = refs->items[i].util;
+
+		if (!(object->flags & REF_HANDLED)) {
+			if (object->type & OBJ_TAG)
+				handle_tag(name, (struct tag *)object);
+			else {
+				if (!prefixcmp(name, "refs/tags/") &&
+				    (tag_of_filtered_mode != REWRITE ||
+				     !get_object_mark(object)))
+					continue;
+				handle_reset(name, object);
+				object->flags |= REF_HANDLED;
+			}
+		}
+	}
+
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
 		const char *name = extra_refs->items[i].string;
 		struct object *object = extra_refs->items[i].util;
@@ -634,7 +659,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info revs;
 	struct object_array commits = OBJECT_ARRAY_INIT;
-	struct string_list extra_refs = STRING_LIST_INIT_NODUP;
+	struct string_list refs = STRING_LIST_INIT_NODUP, extra_refs = STRING_LIST_INIT_NODUP;
 	struct commit *commit;
 	char *export_filename = NULL, *import_filename = NULL;
 	struct option options[] = {
@@ -684,7 +709,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 	if (import_filename && revs.prune_data.nr)
 		full_tree = 1;
 
-	get_tags_and_duplicates(&revs.pending, &extra_refs);
+	get_tags_and_duplicates(&revs.pending, &refs, &extra_refs);
 
 	if (prepare_revision_walk(&revs))
 		die("revision walk setup failed");
@@ -696,11 +721,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 		}
 		else {
 			handle_commit(commit, &revs);
+			commit->object.flags |= REF_HANDLED;
 			handle_tail(&commits, &revs);
 		}
 	}
 
-	handle_tags_and_duplicates(&extra_refs);
+	handle_tags_and_duplicates(&refs, &extra_refs);
 
 	if (export_filename)
 		export_marks(export_filename);
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 57569a7eed..e47b7ac879 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -446,7 +446,7 @@ from $(git rev-parse master)
 
 EOF
 
-test_expect_failure 'refs are updated even if no commits need to be exported' '
+test_expect_success 'refs are updated even if no commits need to be exported' '
 	git fast-export master..master > actual &&
 	test_cmp expected actual
 '

From 04d4b52cc1ea683d0a84a432dfff304353be4c56 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Fri, 15 Jul 2011 16:37:28 +0200
Subject: [PATCH 3561/3720] t5800: test pushing a new branch with old content

This works now that fast-export has been fixed to properly handle
refs that point to a commit that was not exported during the current
fast-export run.
---
 t/t5800-remote-helpers.sh | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 5702334510..12ced2b922 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -138,6 +138,14 @@ test_expect_success 'push new branch by name' '
 	compare_refs clone HEAD server refs/heads/new-name
 '
 
+test_expect_failure 'push new branch with old content' '
+	(cd clone &&
+	 git checkout -b existing &&
+	 git push origin existing
+	) &&
+	compare_refs clone refs/heads/existing server refs/heads/existing
+'
+
 test_expect_failure 'push new branch with old:new refspec' '
 	(cd clone &&
 	 git push origin new-name:new-refspec

From 3932883c293f362b7ee852dd6675dcaa647c1415 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Fri, 15 Jul 2011 21:55:01 +0200
Subject: [PATCH 3562/3720] t5800: point out that deleting branches does not
 work

This test actually breaks the repositories involved somehow, so it is
not enabled by default.
---
 t/t5800-remote-helpers.sh | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 12ced2b922..4664696d00 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -138,7 +138,7 @@ test_expect_success 'push new branch by name' '
 	compare_refs clone HEAD server refs/heads/new-name
 '
 
-test_expect_failure 'push new branch with old content' '
+test_expect_success 'push new branch with old content' '
 	(cd clone &&
 	 git checkout -b existing &&
 	 git push origin existing
@@ -146,6 +146,17 @@ test_expect_failure 'push new branch with old content' '
 	compare_refs clone refs/heads/existing server refs/heads/existing
 '
 
+test_expect_failure BROKEN 'delete branch' '
+	(cd clone &&
+	 git checkout -b delete-me &&
+	 echo content >>file &&
+	 git commit -a -m eight &&
+	 git push origin delete-me
+	 git push origin :delete-me) &&
+	test_must_fail git --git-dir="server/.git" rev-parse --verify delete-me
+'
+
+
 test_expect_failure 'push new branch with old:new refspec' '
 	(cd clone &&
 	 git push origin new-name:new-refspec

From 3e8a63e8d5008132d3c75e3986f8abc084410fe8 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sat, 28 Aug 2010 20:49:01 -0500
Subject: [PATCH 3563/3720] transport-helper: add trailing --

---
 transport-helper.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/transport-helper.c b/transport-helper.c
index 61c928f6cd..57069432ab 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -398,7 +398,7 @@ static int get_exporter(struct transport *transport,
 	/* we need to duplicate helper->in because we want to use it after
 	 * fastexport is done with it. */
 	fastexport->out = dup(helper->in);
-	fastexport->argv = xcalloc(5 + revlist_args->nr, sizeof(*fastexport->argv));
+	fastexport->argv = xcalloc(6 + revlist_args->nr, sizeof(*fastexport->argv));
 	fastexport->argv[argc++] = "fast-export";
 	fastexport->argv[argc++] = "--use-done-feature";
 	if (data->export_marks)
@@ -409,6 +409,8 @@ static int get_exporter(struct transport *transport,
 	for (i = 0; i < revlist_args->nr; i++)
 		fastexport->argv[argc++] = revlist_args->items[i].string;
 
+	fastexport->argv[argc++] = "--";
+
 	fastexport->git_cmd = 1;
 	return start_command(fastexport);
 }

From adf30ac76f65b118b9fb07f1b4423f7c2956ff6b Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 00:06:00 +0200
Subject: [PATCH 3564/3720] remote-helper: check helper status after
 import/export

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/clone.c    |  4 +++-
 transport-helper.c | 16 ++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index bbd5c96237..8e76a747aa 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -821,7 +821,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 			}
 
 		if (!is_local && !complete_refs_before_fetch)
-			transport_fetch_refs(transport, mapped_refs);
+			if (transport_fetch_refs(transport, mapped_refs))
+				die(_("could not fetch refs from %s"),
+				    transport->url);
 
 		remote_head = find_ref_by_name(refs, "HEAD");
 		remote_head_points_at =
diff --git a/transport-helper.c b/transport-helper.c
index 57069432ab..3b6a9fa53d 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -415,6 +415,19 @@ static int get_exporter(struct transport *transport,
 	return start_command(fastexport);
 }
 
+static void check_helper_status(struct helper_data *data)
+{
+	int pid, status;
+
+	pid = waitpid(data->helper->pid, &status, WNOHANG);
+	if (pid < 0)
+		die("Could not retrieve status of remote helper '%s'",
+		    data->name);
+	if (pid > 0 && WIFEXITED(status))
+		die("Remote helper '%s' died with %d",
+		    data->name, WEXITSTATUS(status));
+}
+
 static int fetch_with_import(struct transport *transport,
 			     int nr_heads, struct ref **to_fetch)
 {
@@ -443,6 +456,8 @@ static int fetch_with_import(struct transport *transport,
 
 	if (finish_command(&fastimport))
 		die("Error while running fast-import");
+	check_helper_status(data);
+
 	free(fastimport.argv);
 	fastimport.argv = NULL;
 
@@ -771,6 +786,7 @@ static int push_refs_with_export(struct transport *transport,
 
 	if (finish_command(&exporter))
 		die("Error while running fast-export");
+	check_helper_status(data);
 	push_update_refs_status(data, remote_refs);
 	return 0;
 }

From f02f2e0752d49e834baa973136ecaed680c47fdf Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 00:11:18 +0200
Subject: [PATCH 3565/3720] remote-testgit: factor out RemoteHelper class

Facilitate writing import-export based helpers in python by
refactoring common code to a base class.

[jes: rebased to newer upstream Git]

Signed-off-by: Sverre Rabbelier 
Signed-off-by: Johannes Schindelin 
---
 git-remote-testgit.py              | 295 ++++++-----------------------
 git_remote_helpers/git/importer.py |  28 +--
 git_remote_helpers/helper.py       | 207 ++++++++++++++++++++
 3 files changed, 267 insertions(+), 263 deletions(-)
 create mode 100644 git_remote_helpers/helper.py

diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index 5f3ebd244d..d57c1dc393 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -1,272 +1,95 @@
 #!/usr/bin/env python
 
-# This command is a simple remote-helper, that is used both as a
-# testcase for the remote-helper functionality, and as an example to
-# show remote-helper authors one possible implementation.
-#
-# This is a Git <-> Git importer/exporter, that simply uses git
-# fast-import and git fast-export to consume and produce fast-import
-# streams.
-#
-# To understand better the way things work, one can activate debug
-# traces by setting (to any value) the environment variables
-# GIT_TRANSPORT_HELPER_DEBUG and GIT_DEBUG_TESTGIT, to see messages
-# from the transport-helper side, or from this example remote-helper.
-
-# hashlib is only available in python >= 2.5
-try:
-    import hashlib
-    _digest = hashlib.sha1
-except ImportError:
-    import sha
-    _digest = sha.new
 import sys
 import os
-import time
 sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
 
-from git_remote_helpers.util import die, debug, warn
+from git_remote_helpers.helper import RemoteHelper
+from git_remote_helpers.util import check_output, debug
 from git_remote_helpers.git.repo import GitRepo
 from git_remote_helpers.git.exporter import GitExporter
 from git_remote_helpers.git.importer import GitImporter
 from git_remote_helpers.git.non_local import NonLocalGit
 
-def get_repo(alias, url):
-    """Returns a git repository object initialized for usage.
-    """
 
-    repo = GitRepo(url)
-    repo.get_revs()
-    repo.get_head()
+class TestgitRemoteHelper(RemoteHelper):
+    def get_repo(self, alias, url):
+        """Returns a git repository object initialized for usage.
+        """
 
-    hasher = _digest()
-    hasher.update(repo.path)
-    repo.hash = hasher.hexdigest()
+        repo = GitRepo(url)
+        repo.get_revs()
+        repo.get_head()
 
-    repo.get_base_path = lambda base: os.path.join(
-        base, 'info', 'fast-import', repo.hash)
+        prefix = 'refs/testgit/%s/' % alias
+        debug("prefix: '%s'", prefix)
 
-    prefix = 'refs/testgit/%s/' % alias
-    debug("prefix: '%s'", prefix)
+        repo.marksfile = 'testgit.marks'
+        repo.prefix = prefix
 
-    repo.gitdir = os.environ["GIT_DIR"]
-    repo.alias = alias
-    repo.prefix = prefix
+        self.setup_repo(repo, alias)
 
-    repo.exporter = GitExporter(repo)
-    repo.importer = GitImporter(repo)
-    repo.non_local = NonLocalGit(repo)
+        repo.exporter = GitExporter(repo)
+        repo.importer = GitImporter(repo)
+        repo.non_local = NonLocalGit(repo)
 
-    return repo
-
-
-def local_repo(repo, path):
-    """Returns a git repository object initalized for usage.
-    """
-
-    local = GitRepo(path)
-
-    local.non_local = None
-    local.gitdir = repo.gitdir
-    local.alias = repo.alias
-    local.prefix = repo.prefix
-    local.hash = repo.hash
-    local.get_base_path = repo.get_base_path
-    local.exporter = GitExporter(local)
-    local.importer = GitImporter(local)
-
-    return local
-
-
-def do_capabilities(repo, args):
-    """Prints the supported capabilities.
-    """
-
-    print "import"
-    print "export"
-    print "refspec refs/heads/*:%s*" % repo.prefix
-
-    dirname = repo.get_base_path(repo.gitdir)
-
-    if not os.path.exists(dirname):
-        os.makedirs(dirname)
-
-    path = os.path.join(dirname, 'testgit.marks')
-
-    print "*export-marks %s" % path
-    if os.path.exists(path):
-        print "*import-marks %s" % path
-
-    print # end capabilities
-
-
-def do_list(repo, args):
-    """Lists all known references.
-
-    Bug: This will always set the remote head to master for non-local
-    repositories, since we have no way of determining what the remote
-    head is at clone time.
-    """
-
-    for ref in repo.revs:
-        debug("? refs/heads/%s", ref)
-        print "? refs/heads/%s" % ref
-
-    if repo.head:
-        debug("@refs/heads/%s HEAD" % repo.head)
-        print "@refs/heads/%s HEAD" % repo.head
-    else:
-        debug("@refs/heads/master HEAD")
-        print "@refs/heads/master HEAD"
-
-    print # end list
-
-
-def update_local_repo(repo):
-    """Updates (or clones) a local repo.
-    """
-
-    if repo.local:
         return repo
 
-    path = repo.non_local.clone(repo.gitdir)
-    repo.non_local.update(repo.gitdir)
-    repo = local_repo(repo, path)
-    return repo
+    def local_repo(self, repo, path):
+        """Returns a git repository object initalized for usage.
+        """
 
+        local = GitRepo(path)
 
-def do_import(repo, args):
-    """Exports a fast-import stream from testgit for git to import.
-    """
+        self.setup_local_repo(local, repo)
 
-    if len(args) != 1:
-        die("Import needs exactly one ref")
+        local.exporter = GitExporter(local)
+        local.importer = GitImporter(local)
 
-    if not repo.gitdir:
-        die("Need gitdir to import")
+        return local
 
-    ref = args[0]
-    refs = [ref]
+    def do_list(self, repo, args):
+        """Lists all known references.
 
-    while True:
-        line = sys.stdin.readline()
-        if line == '\n':
-            break
-        if not line.startswith('import '):
-            die("Expected import line.")
+        Bug: This will always set the remote head to master for non-local
+        repositories, since we have no way of determining what the remote
+        head is at clone time.
+        """
 
-        # strip of leading 'import '
-        ref = line[7:].strip()
-        refs.append(ref)
+        for ref in repo.revs:
+            debug("? refs/heads/%s", ref)
+            print "? refs/heads/%s" % ref
 
-    repo = update_local_repo(repo)
-    repo.exporter.export_repo(repo.gitdir, refs)
+        if repo.head:
+            debug("@refs/heads/%s HEAD" % repo.head)
+            print "@refs/heads/%s HEAD" % repo.head
+        else:
+            debug("@refs/heads/master HEAD")
+            print "@refs/heads/master HEAD"
 
-    print "done"
+        print # end list
 
+    def sanitize(self, value):
+        """Cleans up the url.
+        """
 
-def do_export(repo, args):
-    """Imports a fast-import stream from git to testgit.
-    """
+        if value.startswith('testgit::'):
+            value = value[9:]
 
-    if not repo.gitdir:
-        die("Need gitdir to export")
+        return value
 
-    update_local_repo(repo)
-    changed = repo.importer.do_import(repo.gitdir)
+    def get_refs(self, repo, gitdir):
+        """Returns a dictionary with refs.
+        """
+        args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
+        lines = check_output(args).strip().split('\n')
+        refs = {}
+        for line in lines:
+            value, name = line.split(' ')
+            name = name.strip('commit\t')
+            refs[name] = value
+        return refs
 
-    if not repo.local:
-        repo.non_local.push(repo.gitdir)
-
-    for ref in changed:
-        print "ok %s" % ref
-    print
-
-
-COMMANDS = {
-    'capabilities': do_capabilities,
-    'list': do_list,
-    'import': do_import,
-    'export': do_export,
-}
-
-
-def sanitize(value):
-    """Cleans up the url.
-    """
-
-    if value.startswith('testgit::'):
-        value = value[9:]
-
-    return value
-
-
-def read_one_line(repo):
-    """Reads and processes one command.
-    """
-
-    sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
-    if sleepy:
-        debug("Sleeping %d sec before readline" % int(sleepy))
-        time.sleep(int(sleepy))
-
-    line = sys.stdin.readline()
-
-    cmdline = line
-
-    if not cmdline:
-        warn("Unexpected EOF")
-        return False
-
-    cmdline = cmdline.strip().split()
-    if not cmdline:
-        # Blank line means we're about to quit
-        return False
-
-    cmd = cmdline.pop(0)
-    debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
-
-    if cmd not in COMMANDS:
-        die("Unknown command, %s", cmd)
-
-    func = COMMANDS[cmd]
-    func(repo, cmdline)
-    sys.stdout.flush()
-
-    return True
-
-
-def main(args):
-    """Starts a new remote helper for the specified repository.
-    """
-
-    if len(args) != 3:
-        die("Expecting exactly three arguments.")
-        sys.exit(1)
-
-    if os.getenv("GIT_DEBUG_TESTGIT"):
-        import git_remote_helpers.util
-        git_remote_helpers.util.DEBUG = True
-
-    alias = sanitize(args[1])
-    url = sanitize(args[2])
-
-    if not alias.isalnum():
-        warn("non-alnum alias '%s'", alias)
-        alias = "tmp"
-
-    args[1] = alias
-    args[2] = url
-
-    repo = get_repo(alias, url)
-
-    debug("Got arguments %s", args[1:])
-
-    more = True
-
-    sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
-    while (more):
-        more = read_one_line(repo)
 
 if __name__ == '__main__':
-    sys.exit(main(sys.argv))
+    sys.exit(TestgitRemoteHelper().main(sys.argv))
diff --git a/git_remote_helpers/git/importer.py b/git_remote_helpers/git/importer.py
index 5c6b595e16..02a719ac02 100644
--- a/git_remote_helpers/git/importer.py
+++ b/git_remote_helpers/git/importer.py
@@ -1,7 +1,7 @@
 import os
 import subprocess
 
-from git_remote_helpers.util import check_call, check_output
+from git_remote_helpers.util import check_call
 
 
 class GitImporter(object):
@@ -16,18 +16,6 @@ class GitImporter(object):
 
         self.repo = repo
 
-    def get_refs(self, gitdir):
-        """Returns a dictionary with refs.
-        """
-        args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
-        lines = check_output(args).strip().split('\n')
-        refs = {}
-        for line in lines:
-            value, name = line.split(' ')
-            name = name.strip('commit\t')
-            refs[name] = value
-        return refs
-
     def do_import(self, base):
         """Imports a fast-import stream to the given directory.
 
@@ -44,23 +32,9 @@ class GitImporter(object):
         if not os.path.exists(dirname):
             os.makedirs(dirname)
 
-        refs_before = self.get_refs(gitdir)
-
         args = ["git", "--git-dir=" + gitdir, "fast-import", "--quiet", "--export-marks=" + path]
 
         if os.path.exists(path):
             args.append("--import-marks=" + path)
 
         check_call(args)
-
-        refs_after = self.get_refs(gitdir)
-
-        changed = {}
-
-        for name, value in refs_after.iteritems():
-            if refs_before.get(name) == value:
-                continue
-
-            changed[name] = value
-
-        return changed
diff --git a/git_remote_helpers/helper.py b/git_remote_helpers/helper.py
new file mode 100644
index 0000000000..56ed1dad5b
--- /dev/null
+++ b/git_remote_helpers/helper.py
@@ -0,0 +1,207 @@
+import os
+import sys
+import time
+
+# hashlib is only available in python >= 2.5
+try:
+    import hashlib
+    _digest = hashlib.sha1
+except ImportError:
+    import sha
+    _digest = sha.new
+
+from git_remote_helpers.util import debug, die, warn
+
+
+class RemoteHelper(object):
+    def __init__(self):
+        self.commands = {
+            'capabilities': self.do_capabilities,
+            'list': self.do_list,
+            'import': self.do_import,
+            'export': self.do_export,
+        }
+
+    def setup_repo(self, repo, alias):
+        """Returns a git repository object initialized for usage.
+        """
+
+        hasher = _digest()
+        hasher.update(repo.path)
+        repo.hash = hasher.hexdigest()
+
+        repo.get_base_path = lambda base: os.path.join(
+            base, 'info', 'fast-import', repo.hash)
+
+        repo.gitdir = os.environ["GIT_DIR"]
+        repo.alias = alias
+
+    def setup_local_repo(self, local, repo):
+        """Returns a git repository object initalized for usage.
+        """
+        local.non_local = None
+        local.gitdir = repo.gitdir
+        local.alias = repo.alias
+        local.prefix = repo.prefix
+        local.hash = repo.hash
+        local.get_base_path = repo.get_base_path
+
+    def do_capabilities(self, repo, args):
+        """Prints the supported capabilities.
+        """
+
+        print "import"
+        print "export"
+        print "refspec refs/heads/*:%s*" % repo.prefix
+
+        dirname = repo.get_base_path(repo.gitdir)
+
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+
+        path = os.path.join(dirname, repo.marksfile)
+
+        print "*export-marks %s" % path
+        if os.path.exists(path):
+            print "*import-marks %s" % path
+
+        print # end capabilities
+
+    def update_local_repo(self, repo):
+        """Updates (or clones) a local repo.
+        """
+
+        if repo.local:
+            return repo
+
+        path = repo.non_local.clone(repo.gitdir)
+        repo.non_local.update(repo.gitdir)
+        repo = self.local_repo(repo, path)
+        return repo
+
+    def do_import(self, repo, args):
+        """Exports a fast-import stream from testgit for git to import.
+        """
+
+        if len(args) != 1:
+            die("Import needs exactly one ref")
+
+        if not repo.gitdir:
+            die("Need gitdir to import")
+
+        ref = args[0]
+        refs = [ref]
+
+        while True:
+            line = sys.stdin.readline()
+            if line == '\n':
+                break
+            if not line.startswith('import '):
+                die("Expected import line.")
+
+            # strip of leading 'import '
+            ref = line[7:].strip()
+            refs.append(ref)
+
+        repo = self.update_local_repo(repo)
+
+        repo.exporter.export_repo(repo.gitdir, refs)
+
+        print "done"
+
+    def do_export(self, repo, args):
+        """Imports a fast-import stream from git to testgit.
+        """
+
+        if not repo.gitdir:
+            die("Need gitdir to export")
+
+        localrepo = self.update_local_repo(repo)
+
+        refs_before = self.get_refs(repo, repo.gitdir)
+        localrepo.importer.do_import(localrepo.gitdir)
+        refs_after = self.get_refs(repo, repo.gitdir)
+
+        changed = {}
+
+        for name, value in refs_after.iteritems():
+            if refs_before.get(name) == value:
+                continue
+
+            changed[name] = value
+
+        if not repo.local:
+            repo.non_local.push(repo.gitdir)
+
+        for ref in changed:
+            print "ok %s" % ref
+        print
+
+    def read_one_line(self, repo):
+        """Reads and processes one command.
+        """
+
+        sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
+        if sleepy:
+            debug("Sleeping %d sec before readline" % int(sleepy))
+            time.sleep(int(sleepy))
+
+        line = sys.stdin.readline()
+
+        cmdline = line
+
+        if not cmdline:
+            warn("Unexpected EOF")
+            return False
+
+        cmdline = cmdline.strip().split()
+        if not cmdline:
+            # Blank line means we're about to quit
+            return False
+
+        cmd = cmdline.pop(0)
+        debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
+
+        if cmd not in self.commands:
+            die("Unknown command, %s", cmd)
+
+        func = self.commands[cmd]
+        func(repo, cmdline)
+        sys.stdout.flush()
+
+        return True
+
+    def main(self, args):
+        """Starts a new remote helper for the specified repository.
+        """
+
+        if len(args) != 3:
+            die("Expecting exactly three arguments.")
+            sys.exit(1)
+
+        if os.getenv("GIT_REMOTE_HELPER_DEBUG"):
+            import git_remote_helpers.util
+            git_remote_helpers.util.DEBUG = True
+
+        alias = self.sanitize(args[1])
+        url = self.sanitize(args[2])
+
+        if not alias.isalnum():
+            warn("non-alnum alias '%s'", alias)
+            alias = "tmp"
+
+        args[1] = alias
+        args[2] = url
+
+        repo = self.get_repo(alias, url)
+
+        debug("Got arguments %s", args[1:])
+
+        more = True
+
+        sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
+        while (more):
+            more = self.read_one_line(repo)
+
+    if __name__ == '__main__':
+        sys.exit(main(sys.argv))

From 50b5841023b7e24e991f65c93e09bb89b839e55d Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 13:43:34 +0200
Subject: [PATCH 3566/3720] git-remote-testgit: make local a function

Other helpers (such as git-remote-hg) require that 'self.local' is a
function, rather than a variable.
---
 git_remote_helpers/git/importer.py | 2 +-
 git_remote_helpers/git/repo.py     | 6 +++---
 git_remote_helpers/helper.py       | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/git_remote_helpers/git/importer.py b/git_remote_helpers/git/importer.py
index 02a719ac02..b7d6107933 100644
--- a/git_remote_helpers/git/importer.py
+++ b/git_remote_helpers/git/importer.py
@@ -23,7 +23,7 @@ class GitImporter(object):
         """
 
         dirname = self.repo.get_base_path(base)
-        if self.repo.local:
+        if self.repo.local():
             gitdir = self.repo.gitpath
         else:
             gitdir = os.path.abspath(os.path.join(dirname, '.git'))
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
index acbf8d7785..4536233868 100644
--- a/git_remote_helpers/git/repo.py
+++ b/git_remote_helpers/git/repo.py
@@ -38,14 +38,14 @@ class GitRepo(object):
         self.path = path
         self.head = None
         self.revmap = {}
-        self.local = not is_remote(self.path)
+        self.local = lambda: not is_remote(self.path)
 
         if(self.path.endswith('.git')):
             self.gitpath = self.path
         else:
             self.gitpath = os.path.join(self.path, '.git')
 
-        if self.local and not os.path.exists(self.gitpath):
+        if self.local() and not os.path.exists(self.gitpath):
             os.makedirs(self.gitpath)
 
     def get_revs(self):
@@ -68,7 +68,7 @@ class GitRepo(object):
         """Determines the head of a local repo.
         """
 
-        if not self.local:
+        if not self.local():
             return
 
         path = os.path.join(self.gitpath, "HEAD")
diff --git a/git_remote_helpers/helper.py b/git_remote_helpers/helper.py
index 56ed1dad5b..20a97b1d96 100644
--- a/git_remote_helpers/helper.py
+++ b/git_remote_helpers/helper.py
@@ -71,7 +71,7 @@ class RemoteHelper(object):
         """Updates (or clones) a local repo.
         """
 
-        if repo.local:
+        if repo.local():
             return repo
 
         path = repo.non_local.clone(repo.gitdir)
@@ -130,7 +130,7 @@ class RemoteHelper(object):
 
             changed[name] = value
 
-        if not repo.local:
+        if not repo.local():
             repo.non_local.push(repo.gitdir)
 
         for ref in changed:

From 29d4a89b12ca7bb35db6fd9800fa6f74a5efa7ba Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 22 Aug 2010 01:22:14 -0500
Subject: [PATCH 3567/3720] git_remote_helpers: add fastimport library

---
 git_remote_helpers/fastimport/__init__.py     |   0
 git_remote_helpers/fastimport/commands.py     | 469 +++++++++++++
 git_remote_helpers/fastimport/dates.py        |  79 +++
 git_remote_helpers/fastimport/errors.py       | 182 +++++
 git_remote_helpers/fastimport/head_tracker.py |  47 ++
 git_remote_helpers/fastimport/helpers.py      |  88 +++
 git_remote_helpers/fastimport/idmapfile.py    |  65 ++
 git_remote_helpers/fastimport/parser.py       | 621 ++++++++++++++++++
 git_remote_helpers/fastimport/processor.py    | 222 +++++++
 git_remote_helpers/setup.py                   |   3 +-
 10 files changed, 1775 insertions(+), 1 deletion(-)
 create mode 100644 git_remote_helpers/fastimport/__init__.py
 create mode 100644 git_remote_helpers/fastimport/commands.py
 create mode 100644 git_remote_helpers/fastimport/dates.py
 create mode 100644 git_remote_helpers/fastimport/errors.py
 create mode 100644 git_remote_helpers/fastimport/head_tracker.py
 create mode 100644 git_remote_helpers/fastimport/helpers.py
 create mode 100644 git_remote_helpers/fastimport/idmapfile.py
 create mode 100644 git_remote_helpers/fastimport/parser.py
 create mode 100644 git_remote_helpers/fastimport/processor.py

diff --git a/git_remote_helpers/fastimport/__init__.py b/git_remote_helpers/fastimport/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/git_remote_helpers/fastimport/commands.py b/git_remote_helpers/fastimport/commands.py
new file mode 100644
index 0000000000..b3c86c4910
--- /dev/null
+++ b/git_remote_helpers/fastimport/commands.py
@@ -0,0 +1,469 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Import command classes."""
+
+import os
+
+# There is a bug in git 1.5.4.3 and older by which unquoting a string consumes
+# one extra character. Set this variable to True to work-around it. It only
+# happens when renaming a file whose name contains spaces and/or quotes, and
+# the symptom is:
+#   % git-fast-import
+#   fatal: Missing space after source: R "file 1.txt" file 2.txt
+# http://git.kernel.org/?p=git/git.git;a=commit;h=c8744d6a8b27115503565041566d97c21e722584
+GIT_FAST_IMPORT_NEEDS_EXTRA_SPACE_AFTER_QUOTE = False
+
+
+# Lists of command names
+COMMAND_NAMES = ['blob', 'checkpoint', 'commit', 'feature', 'progress',
+    'reset', 'tag']
+FILE_COMMAND_NAMES = ['filemodify', 'filedelete', 'filecopy', 'filerename',
+    'filedeleteall']
+
+
+# Feature names
+MULTIPLE_AUTHORS_FEATURE = "multiple-authors"
+COMMIT_PROPERTIES_FEATURE = "commit-properties"
+EMPTY_DIRS_FEATURE = "empty-directories"
+FEATURE_NAMES = [
+    MULTIPLE_AUTHORS_FEATURE,
+    COMMIT_PROPERTIES_FEATURE,
+    EMPTY_DIRS_FEATURE,
+    ]
+
+
+# for classes with no meaningful __str__()
+def _simplerepr(self):
+    return "<%s at 0x%x>" % (self.__class__.__name__, id(self))
+
+# classes that define __str__() should use this instead
+def _detailrepr(self):
+    return ("<%s at 0x%x: %s>"
+            % (self.__class__.__name__, id(self), str(self)))
+
+
+class ImportCommand(object):
+    """Base class for import commands."""
+
+    def __init__(self, name):
+        self.name = name
+        # List of field names not to display
+        self._binary = []
+
+    __repr__ = _simplerepr
+
+    def format(self):
+        """Format this command as a fastimport dump fragment.
+
+        Returns a (possibly multiline) string that, if seen in a
+        fastimport stream, would parse to an equivalent command object.
+        """
+        raise NotImplementedError("abstract method")
+
+    def dump_str(self, names=None, child_lists=None, verbose=False):
+        """Dump fields as a string.
+
+        :param names: the list of fields to include or
+            None for all public fields
+        :param child_lists: dictionary of child command names to
+            fields for that child command to include
+        :param verbose: if True, prefix each line with the command class and
+            display fields as a dictionary; if False, dump just the field
+            values with tabs between them
+        """
+        interesting = {}
+        if names is None:
+            fields = [k for k in self.__dict__.keys() if not k.startswith('_')]
+        else:
+            fields = names
+        for field in fields:
+            value = self.__dict__.get(field)
+            if field in self._binary and value is not None:
+                value = '(...)'
+            interesting[field] = value
+        if verbose:
+            return "%s: %s" % (self.__class__.__name__, interesting)
+        else:
+            return "\t".join([repr(interesting[k]) for k in fields])
+
+
+class _MarkMixin(object):
+    """mixin for fastimport commands with a mark: blob, commit."""
+    def __init__(self, mark, location):
+        self.mark= mark
+        self.location = location
+
+        # Provide a unique id in case the mark is missing
+        if mark is None:
+            self.id = '%s@%d' % (os.path.basename(location[0]), location[1])
+        else:
+            self.id = ':%s' % mark
+
+    def __str__(self):
+        return self.id
+
+    __repr__ = _detailrepr
+
+
+class BlobCommand(ImportCommand, _MarkMixin):
+
+    def __init__(self, mark, data, location):
+        ImportCommand.__init__(self, 'blob')
+        _MarkMixin.__init__(self, mark, location)
+        self.data = data
+        self._binary = ['data']
+
+    def format(self):
+        if self.mark is None:
+            mark_line = ""
+        else:
+            mark_line = "\nmark :%s" % self.mark
+        return "blob%s\ndata %d\n%s" % (mark_line, len(self.data), self.data)
+
+
+class CheckpointCommand(ImportCommand):
+
+    def __init__(self):
+        ImportCommand.__init__(self, 'checkpoint')
+
+    def format(self):
+        return "checkpoint"
+
+
+class CommitCommand(ImportCommand, _MarkMixin):
+
+    def __init__(self, ref, mark, author, committer, message, from_,
+        merges, file_cmds, location=None, more_authors=None, properties=None):
+        ImportCommand.__init__(self, 'commit')
+        _MarkMixin.__init__(self, mark, location)
+        self.ref = ref
+        self.author = author
+        self.committer = committer
+        self.message = message
+        self.from_ = from_
+        self.merges = merges
+        self.file_cmds = file_cmds
+        self.more_authors = more_authors
+        self.properties = properties
+        self._binary = ['file_cmds']
+
+    def format(self, use_features=True, include_file_contents=True):
+        if self.mark is None:
+            mark_line = ""
+        else:
+            mark_line = "\nmark :%s" % self.mark
+        if self.author is None:
+            author_section = ""
+        else:
+            author_section = "\nauthor %s" % format_who_when(self.author)
+            if use_features and self.more_authors:
+                for author in self.more_authors:
+                    author_section += "\nauthor %s" % format_who_when(author)
+        committer = "committer %s" % format_who_when(self.committer)
+        if self.message is None:
+            msg_section = ""
+        else:
+            msg = self.message.encode('utf8')
+            msg_section = "\ndata %d\n%s" % (len(msg), msg)
+        if self.from_ is None:
+            from_line = ""
+        else:
+            from_line = "\nfrom %s" % self.from_
+        if self.merges is None:
+            merge_lines = ""
+        else:
+            merge_lines = "".join(["\nmerge %s" % (m,)
+                for m in self.merges])
+        if use_features and self.properties:
+            property_lines = []
+            for name in sorted(self.properties):
+                value = self.properties[name]
+                property_lines.append("\n" + format_property(name, value))
+            properties_section = "".join(property_lines)
+        else:
+            properties_section = ""
+        if self.file_cmds is None:
+            filecommands = ""
+        else:
+            if include_file_contents:
+                format_str = "\n%r"
+            else:
+                format_str = "\n%s"
+            filecommands = "".join(
+                ["\n" + fc.format() for fc in self.file_cmds])
+        return "commit %s%s%s\n%s%s%s%s%s%s" % (self.ref, mark_line,
+            author_section, committer, msg_section, from_line, merge_lines,
+            properties_section, filecommands)
+
+    def dump_str(self, names=None, child_lists=None, verbose=False):
+        result = [ImportCommand.dump_str(self, names, verbose=verbose)]
+        for f in self.file_cmds:
+            if child_lists is None:
+                continue
+            try:
+                child_names = child_lists[f.name]
+            except KeyError:
+                continue
+            result.append("\t%s" % f.dump_str(child_names, verbose=verbose))
+        return '\n'.join(result)
+
+
+class FeatureCommand(ImportCommand):
+
+    def __init__(self, feature_name, value=None, location=None):
+        ImportCommand.__init__(self, 'feature')
+        self.feature_name = feature_name
+        self.value = value
+        self.location = location
+
+    def format(self):
+        if self.value is None:
+            value_text = ""
+        else:
+            value_text = "=%s" % self.value
+        return "feature %s%s" % (self.feature_name, value_text)
+
+
+class ProgressCommand(ImportCommand):
+
+    def __init__(self, message):
+        ImportCommand.__init__(self, 'progress')
+        self.message = message
+
+    def format(self):
+        return "progress %s" % (self.message,)
+
+
+class ResetCommand(ImportCommand):
+
+    def __init__(self, ref, from_):
+        ImportCommand.__init__(self, 'reset')
+        self.ref = ref
+        self.from_ = from_
+
+    def format(self):
+        if self.from_ is None:
+            from_line = ""
+        else:
+            # According to git-fast-import(1), the extra LF is optional here;
+            # however, versions of git up to 1.5.4.3 had a bug by which the LF
+            # was needed. Always emit it, since it doesn't hurt and maintains
+            # compatibility with older versions.
+            # http://git.kernel.org/?p=git/git.git;a=commit;h=655e8515f279c01f525745d443f509f97cd805ab
+            from_line = "\nfrom %s\n" % self.from_
+        return "reset %s%s" % (self.ref, from_line)
+
+
+class TagCommand(ImportCommand):
+
+    def __init__(self, id, from_, tagger, message):
+        ImportCommand.__init__(self, 'tag')
+        self.id = id
+        self.from_ = from_
+        self.tagger = tagger
+        self.message = message
+
+    def __str__(self):
+        return self.id
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        if self.from_ is None:
+            from_line = ""
+        else:
+            from_line = "\nfrom %s" % self.from_
+        if self.tagger is None:
+            tagger_line = ""
+        else:
+            tagger_line = "\ntagger %s" % format_who_when(self.tagger)
+        if self.message is None:
+            msg_section = ""
+        else:
+            msg = self.message.encode('utf8')
+            msg_section = "\ndata %d\n%s" % (len(msg), msg)
+        return "tag %s%s%s%s" % (self.id, from_line, tagger_line, msg_section)
+
+
+class FileCommand(ImportCommand):
+    """Base class for file commands."""
+    pass
+
+
+class FileModifyCommand(FileCommand):
+
+    def __init__(self, path, mode, dataref, data):
+        # Either dataref or data should be null
+        FileCommand.__init__(self, 'filemodify')
+        self.path = check_path(path)
+        self.mode = mode
+        self.dataref = dataref
+        self.data = data
+        self._binary = ['data']
+
+    def __str__(self):
+        return self.path
+
+    __repr__ = _detailrepr
+
+    def format(self, include_file_contents=True):
+        datastr = ""
+        if self.dataref is None:
+            dataref = "inline"
+            if include_file_contents:
+                datastr = "\ndata %d\n%s" % (len(self.data), self.data)
+        else:
+            dataref = "%s" % (self.dataref,)
+        path = format_path(self.path)
+        return "M %s %s %s%s" % (self.mode, dataref, path, datastr)
+
+    def is_regular(self):
+        """Return true if this is a regular file (mode 644)."""
+        return self.mode.endswith("644")
+
+    def is_executable(self):
+        """Return true if this is an executable file (mode 755)."""
+        return self.mode.endswith("755")
+
+    def is_symlink(self):
+        """Return true if this is a symlink (mode 120000)."""
+        return self.mode == "120000"
+
+    def is_gitlink(self):
+        """Return true if this is a gitlink (mode 160000)."""
+        return self.mode == "160000"
+
+
+class FileDeleteCommand(FileCommand):
+
+    def __init__(self, path):
+        FileCommand.__init__(self, 'filedelete')
+        self.path = check_path(path)
+
+    def __str__(self):
+        return self.path
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "D %s" % (format_path(self.path),)
+
+
+class FileCopyCommand(FileCommand):
+
+    def __init__(self, src_path, dest_path):
+        FileCommand.__init__(self, 'filecopy')
+        self.src_path = check_path(src_path)
+        self.dest_path = check_path(dest_path)
+
+    def __str__(self):
+        return "%s -> %s" % (self.src_path, self.dest_path)
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "C %s %s" % (
+            format_path(self.src_path, quote_spaces=True),
+            format_path(self.dest_path))
+
+
+class FileRenameCommand(FileCommand):
+
+    def __init__(self, old_path, new_path):
+        FileCommand.__init__(self, 'filerename')
+        self.old_path = check_path(old_path)
+        self.new_path = check_path(new_path)
+
+    def __str__(self):
+        return "%s -> %s" % (self.old_path, self.new_path)
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "R %s %s" % (
+            format_path(self.old_path, quote_spaces=True),
+            format_path(self.new_path))
+
+
+class FileDeleteAllCommand(FileCommand):
+
+    def __init__(self):
+        FileCommand.__init__(self, 'filedeleteall')
+
+    def format(self):
+        return "deleteall"
+
+
+def check_path(path):
+    """Check that a path is legal.
+
+    :return: the path if all is OK
+    :raise ValueError: if the path is illegal
+    """
+    if path is None or path == '':
+        raise ValueError("illegal path '%s'" % path)
+    return path
+
+
+def format_path(p, quote_spaces=False):
+    """Format a path in utf8, quoting it if necessary."""
+    if '\n' in p:
+        import re
+        p = re.sub('\n', '\\n', p)
+        quote = True
+    else:
+        quote = p[0] == '"' or (quote_spaces and ' ' in p)
+    if quote:
+        extra = GIT_FAST_IMPORT_NEEDS_EXTRA_SPACE_AFTER_QUOTE and ' ' or ''
+        p = '"%s"%s' % (p, extra)
+    return p.encode('utf8')
+
+
+def format_who_when(fields):
+    """Format a tuple of name,email,secs-since-epoch,utc-offset-secs as a string."""
+    offset = fields[3]
+    if offset < 0:
+        offset_sign = '-'
+        offset = abs(offset)
+    else:
+        offset_sign = '+'
+    offset_hours = offset / 3600
+    offset_minutes = offset / 60 - offset_hours * 60
+    offset_str = "%s%02d%02d" % (offset_sign, offset_hours, offset_minutes)
+    name = fields[0]
+    if name == '':
+        sep = ''
+    else:
+        sep = ' '
+    if isinstance(name, unicode):
+        name = name.encode('utf8')
+    email = fields[1]
+    if isinstance(email, unicode):
+        email = email.encode('utf8')
+    result = "%s%s<%s> %d %s" % (name, sep, email, fields[2], offset_str)
+    return result
+
+
+def format_property(name, value):
+    """Format the name and value (both unicode) of a property as a string."""
+    utf8_name = name.encode('utf8')
+    if value is not None:
+        utf8_value = value.encode('utf8')
+        result = "property %s %d %s" % (utf8_name, len(utf8_value), utf8_value)
+    else:
+        result = "property %s" % (utf8_name,)
+    return result
diff --git a/git_remote_helpers/fastimport/dates.py b/git_remote_helpers/fastimport/dates.py
new file mode 100644
index 0000000000..f532b2e249
--- /dev/null
+++ b/git_remote_helpers/fastimport/dates.py
@@ -0,0 +1,79 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Date parsing routines.
+
+Each routine returns timestamp,timezone where
+
+* timestamp is seconds since epoch
+* timezone is the offset from UTC in seconds.
+"""
+
+
+import time
+
+from git_remote_helpers.fastimport import errors
+
+
+def parse_raw(s, lineno=0):
+    """Parse a date from a raw string.
+    
+    The format must be exactly "seconds-since-epoch offset-utc".
+    See the spec for details.
+    """
+    timestamp_str, timezone_str = s.split(' ', 1)
+    timestamp = float(timestamp_str)
+    timezone = _parse_tz(timezone_str, lineno)
+    return timestamp, timezone
+
+
+def _parse_tz(tz, lineno):
+    """Parse a timezone specification in the [+|-]HHMM format.
+
+    :return: the timezone offset in seconds.
+    """
+    # from git_repository.py in bzr-git
+    if len(tz) != 5:
+        raise errors.InvalidTimezone(lineno, tz)
+    sign = {'+': +1, '-': -1}[tz[0]]
+    hours = int(tz[1:3])
+    minutes = int(tz[3:])
+    return sign * 60 * (60 * hours + minutes)
+
+
+def parse_rfc2822(s, lineno=0):
+    """Parse a date from a rfc2822 string.
+    
+    See the spec for details.
+    """
+    raise NotImplementedError(parse_rfc2822)
+
+
+def parse_now(s, lineno=0):
+    """Parse a date from a string.
+
+    The format must be exactly "now".
+    See the spec for details.
+    """
+    return time.time(), 0
+
+
+# Lookup tabel of date parsing routines
+DATE_PARSERS_BY_NAME = {
+    'raw':      parse_raw,
+    'rfc2822':  parse_rfc2822,
+    'now':      parse_now,
+    }
diff --git a/git_remote_helpers/fastimport/errors.py b/git_remote_helpers/fastimport/errors.py
new file mode 100644
index 0000000000..b8cf26fd09
--- /dev/null
+++ b/git_remote_helpers/fastimport/errors.py
@@ -0,0 +1,182 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Exception classes for fastimport"""
+
+
+class FastImportError(StandardError):
+    """The base exception class for all import processing exceptions."""
+
+    _fmt = "Unknown Import Error"
+
+    def __str__(self):
+        return self._fmt % self.__dict__
+
+class ParsingError(FastImportError):
+    """The base exception class for all import processing exceptions."""
+
+    _fmt = "Unknown Import Parsing Error"
+
+    def __init__(self, filename, lineno):
+        FastImportError.__init__(self)
+        self.filename = filename
+        self.lineno = lineno
+
+    def __str__(self):
+        result = []
+        if self.filename:
+            result.append(self.filename)
+            result.append(", ")
+        result.append("line ")
+        result.append(str(self.lineno))
+        result.append(": ")
+        result.append(FastImportError.__str__(self))
+        return "".join(result)
+
+
+class MissingBytes(ParsingError):
+    """Raised when EOF encountered while expecting to find more bytes."""
+
+    _fmt = ("Unexpected EOF - expected %(expected)d bytes,"
+        " found %(found)d")
+
+    def __init__(self, filename, lineno, expected, found):
+        ParsingError.__init__(self, filename, lineno)
+        self.expected = expected
+        self.found = found
+
+
+class MissingTerminator(ParsingError):
+    """Raised when EOF encountered while expecting to find a terminator."""
+
+    _fmt = "Unexpected EOF - expected '%(terminator)s' terminator"
+
+    def __init__(self, filename, lineno, terminator):
+        ParsingError.__init__(self, filename, lineno)
+        self.terminator = terminator
+
+
+class InvalidCommand(ParsingError):
+    """Raised when an unknown command found."""
+
+    _fmt = ("Invalid command '%(cmd)s'")
+
+    def __init__(self, filename, lineno, cmd):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+
+
+class MissingSection(ParsingError):
+    """Raised when a section is required in a command but not present."""
+
+    _fmt = ("Command %(cmd)s is missing section %(section)s")
+
+    def __init__(self, filename, lineno, cmd, section):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+        self.section = section
+
+
+class BadFormat(ParsingError):
+    """Raised when a section is formatted incorrectly."""
+
+    _fmt = ("Bad format for section %(section)s in "
+            "command %(cmd)s: found '%(text)s'")
+
+    def __init__(self, filename, lineno, cmd, section, text):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+        self.section = section
+        self.text = text
+
+
+class InvalidTimezone(ParsingError):
+    """Raised when converting a string timezone to a seconds offset."""
+
+    _fmt = "Timezone %(timezone)r could not be converted.%(reason)s"
+
+    def __init__(self, filename, lineno, timezone, reason=None):
+        ParsingError.__init__(self, filename, lineno)
+        self.timezone = timezone
+        if reason:
+            self.reason = ' ' + reason
+        else:
+            self.reason = ''
+
+
+class UnknownDateFormat(FastImportError):
+    """Raised when an unknown date format is given."""
+
+    _fmt = ("Unknown date format '%(format)s'")
+
+    def __init__(self, format):
+        FastImportError.__init__(self)
+        self.format = format
+
+
+class MissingHandler(FastImportError):
+    """Raised when a processor can't handle a command."""
+
+    _fmt = ("Missing handler for command %(cmd)s")
+
+    def __init__(self, cmd):
+        FastImportError.__init__(self)
+        self.cmd = cmd
+
+
+class UnknownParameter(FastImportError):
+    """Raised when an unknown parameter is passed to a processor."""
+
+    _fmt = ("Unknown parameter - '%(param)s' not in %(knowns)s")
+
+    def __init__(self, param, knowns):
+        FastImportError.__init__(self)
+        self.param = param
+        self.knowns = knowns
+
+
+class BadRepositorySize(FastImportError):
+    """Raised when the repository has an incorrect number of revisions."""
+
+    _fmt = ("Bad repository size - %(found)d revisions found, "
+        "%(expected)d expected")
+
+    def __init__(self, expected, found):
+        FastImportError.__init__(self)
+        self.expected = expected
+        self.found = found
+
+
+class BadRestart(FastImportError):
+    """Raised when the import stream and id-map do not match up."""
+
+    _fmt = ("Bad restart - attempted to skip commit %(commit_id)s "
+        "but matching revision-id is unknown")
+
+    def __init__(self, commit_id):
+        FastImportError.__init__(self)
+        self.commit_id = commit_id
+
+
+class UnknownFeature(FastImportError):
+    """Raised when an unknown feature is given in the input stream."""
+
+    _fmt = ("Unknown feature '%(feature)s' - try a later importer or "
+        "an earlier data format")
+
+    def __init__(self, feature):
+        FastImportError.__init__(self)
+        self.feature = feature
diff --git a/git_remote_helpers/fastimport/head_tracker.py b/git_remote_helpers/fastimport/head_tracker.py
new file mode 100644
index 0000000000..ad6b48c8b8
--- /dev/null
+++ b/git_remote_helpers/fastimport/head_tracker.py
@@ -0,0 +1,47 @@
+
+
+class HeadTracker(object):
+    """
+    Keep track of the heads in a fastimport stream.
+    """
+    def __init__(self):
+        self.last_ref = None
+
+        # map git ref name (e.g. "refs/heads/master") to id of last
+        # commit with that ref
+        self.last_ids = {}
+
+        # the set of heads seen so far in the stream, as a mapping
+        # from commit id of the head to set of ref names
+        self.heads = {}
+
+    def track_heads(self, cmd):
+        """Track the repository heads given a CommitCommand.
+        
+        :param cmd: the CommitCommand
+        :return: the list of parents in terms of commit-ids
+        """
+        # Get the true set of parents
+        if cmd.from_ is not None:
+            parents = [cmd.from_]
+        else:
+            last_id = self.last_ids.get(cmd.ref)
+            if last_id is not None:
+                parents = [last_id]
+            else:
+                parents = []
+        parents.extend(cmd.merges)
+
+        # Track the heads
+        self.track_heads_for_ref(cmd.ref, cmd.id, parents)
+        return parents
+
+    def track_heads_for_ref(self, cmd_ref, cmd_id, parents=None):
+        if parents is not None:
+            for parent in parents:
+                if parent in self.heads:
+                    del self.heads[parent]
+        self.heads.setdefault(cmd_id, set()).add(cmd_ref)
+        self.last_ids[cmd_ref] = cmd_id
+        self.last_ref = cmd_ref
+    
diff --git a/git_remote_helpers/fastimport/helpers.py b/git_remote_helpers/fastimport/helpers.py
new file mode 100644
index 0000000000..3ce5a98e17
--- /dev/null
+++ b/git_remote_helpers/fastimport/helpers.py
@@ -0,0 +1,88 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Miscellaneous useful stuff."""
+
+import os
+
+def single_plural(n, single, plural):
+    """Return a single or plural form of a noun based on number."""
+    if n == 1:
+        return single
+    else:
+        return plural
+
+
+def invert_dict(d):
+    """Invert a dictionary with keys matching each value turned into a list."""
+    # Based on recipe from ASPN
+    result = {}
+    for k, v in d.iteritems():
+        keys = result.setdefault(v, [])
+        keys.append(k)
+    return result
+
+
+def invert_dictset(d):
+    """Invert a dictionary with keys matching a set of values, turned into lists."""
+    # Based on recipe from ASPN
+    result = {}
+    for k, c in d.iteritems():
+        for v in c:
+            keys = result.setdefault(v, [])
+            keys.append(k)
+    return result
+
+
+def _common_path_and_rest(l1, l2, common=[]):
+    # From http://code.activestate.com/recipes/208993/
+    if len(l1) < 1: return (common, l1, l2)
+    if len(l2) < 1: return (common, l1, l2)
+    if l1[0] != l2[0]: return (common, l1, l2)
+    return _common_path_and_rest(l1[1:], l2[1:], common+[l1[0]])
+
+
+def common_path(path1, path2):
+    """Find the common bit of 2 paths."""
+    return ''.join(_common_path_and_rest(path1, path2)[0])
+
+
+def common_directory(paths):
+    """Find the deepest common directory of a list of paths.
+    
+    :return: if no paths are provided, None is returned;
+      if there is no common directory, '' is returned;
+      otherwise the common directory with a trailing / is returned.
+    """
+    def get_dir_with_slash(path):
+        if path == '' or path.endswith('/'):
+            return path
+        else:
+            dirname, basename = os.path.split(path)
+            if dirname == '':
+                return dirname
+            else:
+                return dirname + '/'
+
+    if not paths:
+        return None
+    elif len(paths) == 1:
+        return get_dir_with_slash(paths[0])
+    else:
+        common = common_path(paths[0], paths[1])
+        for path in paths[2:]:
+            common = common_path(common, path)
+        return get_dir_with_slash(common)
diff --git a/git_remote_helpers/fastimport/idmapfile.py b/git_remote_helpers/fastimport/idmapfile.py
new file mode 100644
index 0000000000..7b4ccf4afe
--- /dev/null
+++ b/git_remote_helpers/fastimport/idmapfile.py
@@ -0,0 +1,65 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Routines for saving and loading the id-map file."""
+
+import os
+
+
+def save_id_map(filename, revision_ids):
+    """Save the mapping of commit ids to revision ids to a file.
+
+    Throws the usual exceptions if the file cannot be opened,
+    written to or closed.
+
+    :param filename: name of the file to save the data to
+    :param revision_ids: a dictionary of commit ids to revision ids.
+    """
+    f = open(filename, 'wb')
+    try:
+        for commit_id, rev_id in revision_ids.iteritems():
+            f.write("%s %s\n" % (commit_id, rev_id))
+        f.flush()
+    finally:
+        f.close()
+
+
+def load_id_map(filename):
+    """Load the mapping of commit ids to revision ids from a file.
+
+    If the file does not exist, an empty result is returned.
+    If the file does exists but cannot be opened, read or closed,
+    the normal exceptions are thrown.
+
+    NOTE: It is assumed that commit-ids do not have embedded spaces.
+
+    :param filename: name of the file to save the data to
+    :result: map, count where:
+      map = a dictionary of commit ids to revision ids;
+      count = the number of keys in map
+    """
+    result = {}
+    count = 0
+    if os.path.exists(filename):
+        f = open(filename)
+        try:
+            for line in f:
+                parts = line[:-1].split(' ', 1)
+                result[parts[0]] = parts[1]
+                count += 1
+        finally:
+            f.close()
+    return result, count
diff --git a/git_remote_helpers/fastimport/parser.py b/git_remote_helpers/fastimport/parser.py
new file mode 100644
index 0000000000..f9c2655913
--- /dev/null
+++ b/git_remote_helpers/fastimport/parser.py
@@ -0,0 +1,621 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import warnings
+
+"""Parser of import data into command objects.
+
+In order to reuse existing front-ends, the stream format is a subset of
+the one used by git-fast-import (as of the 1.5.4 release of git at least).
+The grammar is:
+
+  stream ::= cmd*;
+
+  cmd ::= new_blob
+        | new_commit
+        | new_tag
+        | reset_branch
+        | checkpoint
+        | progress
+        ;
+
+  new_blob ::= 'blob' lf
+    mark?
+    file_content;
+  file_content ::= data;
+
+  new_commit ::= 'commit' sp ref_str lf
+    mark?
+    ('author' sp name '<' email '>' when lf)?
+    'committer' sp name '<' email '>' when lf
+    commit_msg
+    ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
+    ('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
+    file_change*
+    lf?;
+  commit_msg ::= data;
+
+  file_change ::= file_clr
+    | file_del
+    | file_rnm
+    | file_cpy
+    | file_obm
+    | file_inm;
+  file_clr ::= 'deleteall' lf;
+  file_del ::= 'D' sp path_str lf;
+  file_rnm ::= 'R' sp path_str sp path_str lf;
+  file_cpy ::= 'C' sp path_str sp path_str lf;
+  file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
+  file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
+    data;
+
+  new_tag ::= 'tag' sp tag_str lf
+    'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
+    'tagger' sp name '<' email '>' when lf
+    tag_msg;
+  tag_msg ::= data;
+
+  reset_branch ::= 'reset' sp ref_str lf
+    ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
+    lf?;
+
+  checkpoint ::= 'checkpoint' lf
+    lf?;
+
+  progress ::= 'progress' sp not_lf* lf
+    lf?;
+
+     # note: the first idnum in a stream should be 1 and subsequent
+     # idnums should not have gaps between values as this will cause
+     # the stream parser to reserve space for the gapped values.  An
+     # idnum can be updated in the future to a new object by issuing
+     # a new mark directive with the old idnum.
+     #
+  mark ::= 'mark' sp idnum lf;
+  data ::= (delimited_data | exact_data)
+    lf?;
+
+    # note: delim may be any string but must not contain lf.
+    # data_line may contain any data but must not be exactly
+    # delim. The lf after the final data_line is included in
+    # the data.
+  delimited_data ::= 'data' sp '<<' delim lf
+    (data_line lf)*
+    delim lf;
+
+     # note: declen indicates the length of binary_data in bytes.
+     # declen does not include the lf preceeding the binary data.
+     #
+  exact_data ::= 'data' sp declen lf
+    binary_data;
+
+     # note: quoted strings are C-style quoting supporting \c for
+     # common escapes of 'c' (e..g \n, \t, \\, \") or \nnn where nnn
+     # is the signed byte value in octal.  Note that the only
+     # characters which must actually be escaped to protect the
+     # stream formatting is: \, \" and LF.  Otherwise these values
+     # are UTF8.
+     #
+  ref_str     ::= ref;
+  sha1exp_str ::= sha1exp;
+  tag_str     ::= tag;
+  path_str    ::= path    | '"' quoted(path)    '"' ;
+  mode        ::= '100644' | '644'
+                | '100755' | '755'
+                | '120000'
+                ;
+
+  declen ::= # unsigned 32 bit value, ascii base10 notation;
+  bigint ::= # unsigned integer value, ascii base10 notation;
+  binary_data ::= # file content, not interpreted;
+
+  when         ::= raw_when | rfc2822_when;
+  raw_when     ::= ts sp tz;
+  rfc2822_when ::= # Valid RFC 2822 date and time;
+
+  sp ::= # ASCII space character;
+  lf ::= # ASCII newline (LF) character;
+
+     # note: a colon (':') must precede the numerical value assigned to
+     # an idnum.  This is to distinguish it from a ref or tag name as
+     # GIT does not permit ':' in ref or tag strings.
+     #
+  idnum   ::= ':' bigint;
+  path    ::= # GIT style file path, e.g. \"a/b/c\";
+  ref     ::= # GIT ref name, e.g. \"refs/heads/MOZ_GECKO_EXPERIMENT\";
+  tag     ::= # GIT tag name, e.g. \"FIREFOX_1_5\";
+  sha1exp ::= # Any valid GIT SHA1 expression;
+  hexsha1 ::= # SHA1 in hexadecimal format;
+
+     # note: name and email are UTF8 strings, however name must not
+     # contain '<' or lf and email must not contain any of the
+     # following: '<', '>', lf.
+     #
+  name  ::= # valid GIT author/committer name;
+  email ::= # valid GIT author/committer email;
+  ts    ::= # time since the epoch in seconds, ascii base10 notation;
+  tz    ::= # GIT style timezone;
+
+     # note: comments may appear anywhere in the input, except
+     # within a data command.  Any form of the data command
+     # always escapes the related input from comment processing.
+     #
+     # In case it is not clear, the '#' that starts the comment
+     # must be the first character on that the line (an lf have
+     # preceeded it).
+     #
+  comment ::= '#' not_lf* lf;
+  not_lf  ::= # Any byte that is not ASCII newline (LF);
+"""
+
+
+import re
+import sys
+
+from git_remote_helpers.fastimport import (
+    commands,
+    dates,
+    errors
+    )
+
+
+## Stream parsing ##
+
+class LineBasedParser(object):
+
+    def __init__(self, input, filename=None):
+        """A Parser that keeps track of line numbers.
+
+        :param input: the file-like object to read from
+        """
+        self.input = input
+        if filename is None:
+            try:
+                self.filename = input.name
+            except AttributeError:
+                self.filename = "(unknown)"
+        else:
+            self.filename = filename
+        self.lineno = 0
+        # Lines pushed back onto the input stream
+        self._buffer = []
+
+    def abort(self, exception, *args):
+        """Raise an exception providing line number information."""
+        raise exception(self.filename, self.lineno, *args)
+
+    def readline(self):
+        """Get the next line including the newline or '' on EOF."""
+        self.lineno += 1
+        if self._buffer:
+            return self._buffer.pop()
+        else:
+            return self.input.readline()
+
+    def next_line(self):
+        """Get the next line without the newline or None on EOF."""
+        line = self.readline()
+        if line:
+            return line[:-1]
+        else:
+            return None
+
+    def push_line(self, line):
+        """Push line back onto the line buffer.
+        
+        :param line: the line with no trailing newline
+        """
+        self.lineno -= 1
+        self._buffer.append(line + "\n")
+
+    def read_bytes(self, count):
+        """Read a given number of bytes from the input stream.
+        
+        Throws MissingBytes if the bytes are not found.
+
+        Note: This method does not read from the line buffer.
+
+        :return: a string
+        """
+        result = self.input.read(count)
+        found = len(result)
+        self.lineno += result.count("\n")
+        if found != count:
+            self.abort(errors.MissingBytes, count, found)
+        return result
+
+    def read_until(self, terminator):
+        """Read the input stream until the terminator is found.
+        
+        Throws MissingTerminator if the terminator is not found.
+
+        Note: This method does not read from the line buffer.
+
+        :return: the bytes read up to but excluding the terminator.
+        """
+        
+        lines = []
+        term = terminator + '\n'
+        while True:
+            line = self.input.readline()
+            if line == term:
+                break
+            else:
+                lines.append(line)
+        return ''.join(lines)
+
+
+# Regular expression used for parsing. (Note: The spec states that the name
+# part should be non-empty but git-fast-export doesn't always do that so
+# the first bit is \w*, not \w+.) Also git-fast-import code says the
+# space before the email is optional.
+_WHO_AND_WHEN_RE = re.compile(r'([^<]*)<(.*)> (.+)')
+_WHO_RE = re.compile(r'([^<]*)<(.*)>')
+
+
+class ImportParser(LineBasedParser):
+
+    def __init__(self, input, filename=None):
+        """A Parser of import commands.
+
+        :param input: the file-like object to read from
+        :param verbose: display extra information of not
+        """
+        LineBasedParser.__init__(self, input, filename)
+
+        # We auto-detect the date format when a date is first encountered
+        self.date_parser = None
+
+    def warning(self, msg):
+        sys.stderr.write("warning line %d: %s\n" % (self.lineno, msg))
+
+    def parse(self):
+        """Parse the input stream, yielding a sequence of ImportCommand
+        objects.  Iteration terminates on EOF.  Raises InvalidCommand on
+        parse error."""
+        while True:
+            line = self.next_line()
+            if line is None:
+                break
+            elif len(line) == 0 or line.startswith('#'):
+                continue
+            # Search for commands in order of likelihood
+            elif line.startswith('commit '):
+                yield self._parse_commit(line[len('commit '):])
+            elif line.startswith('blob'):
+                yield self._parse_blob()
+            elif line.startswith('done'):
+                break
+            elif line.startswith('progress '):
+                yield commands.ProgressCommand(line[len('progress '):])
+            elif line.startswith('reset '):
+                yield self._parse_reset(line[len('reset '):])
+            elif line.startswith('tag '):
+                yield self._parse_tag(line[len('tag '):])
+            elif line.startswith('checkpoint'):
+                yield commands.CheckpointCommand()
+            elif line.startswith('feature'):
+                yield self._parse_feature(line[len('feature '):])
+            else:
+                self.abort(errors.InvalidCommand, line)
+
+    def iter_commands(self):
+        warnings.warn("iter_commands() deprecated: use parse()",
+                      DeprecationWarning, stacklevel=2)
+        return self.parse()
+
+    def iter_file_commands(self):
+        """Iterator returning FileCommand objects.
+        
+        If an invalid file command is found, the line is silently
+        pushed back and iteration ends.
+        """
+        while True:
+            line = self.next_line()
+            if line is None:
+                break
+            elif len(line) == 0 or line.startswith('#'):
+                continue
+            # Search for file commands in order of likelihood
+            elif line.startswith('M '):
+                yield self._parse_file_modify(line[2:])
+            elif line.startswith('D '):
+                path = self._path(line[2:])
+                yield commands.FileDeleteCommand(path)
+            elif line.startswith('R '):
+                old, new = self._path_pair(line[2:])
+                yield commands.FileRenameCommand(old, new)
+            elif line.startswith('C '):
+                src, dest = self._path_pair(line[2:])
+                yield commands.FileCopyCommand(src, dest)
+            elif line.startswith('deleteall'):
+                yield commands.FileDeleteAllCommand()
+            else:
+                self.push_line(line)
+                break
+
+    def _parse_blob(self):
+        """Parse a blob command."""
+        location = (self.filename, self.lineno)
+        mark = self._get_mark_if_any()
+        data = self._get_data('blob')
+        return commands.BlobCommand(mark, data, location)
+
+    def _parse_commit(self, ref):
+        """Parse a commit command."""
+        location = (self.filename, self.lineno)
+        mark = self._get_mark_if_any()
+        author = self._get_user_info('commit', 'author', False)
+        more_authors = []
+        while True:
+            another_author = self._get_user_info('commit', 'author', False)
+            if another_author is not None:
+                more_authors.append(another_author)
+            else:
+                break
+        committer = self._get_user_info('commit', 'committer')
+        message = self._get_data('commit', 'message')
+        try:
+            message = message.decode('utf_8')
+        except UnicodeDecodeError:
+            self.warning(
+                "commit message not in utf8 - replacing unknown characters")
+            message = message.decode('utf_8', 'replace')
+        from_ = self._get_from()
+        merges = []
+        while True:
+            merge = self._get_merge()
+            if merge is not None:
+                # while the spec suggests it's illegal, git-fast-export
+                # outputs multiple merges on the one line, e.g.
+                # merge :x :y :z
+                these_merges = merge.split(" ")
+                merges.extend(these_merges)
+            else:
+                break
+        properties = {}
+        while True:
+            name_value = self._get_property()
+            if name_value is not None:
+                name, value = name_value
+                properties[name] = value
+            else:
+                break
+        file_cmds = list(self.iter_file_commands())
+        return commands.CommitCommand(ref, mark, author, committer, message,
+            from_, merges, file_cmds, location,
+            more_authors=more_authors, properties=properties)
+
+    def _parse_feature(self, info):
+        """Parse a feature command."""
+        parts = info.split("=", 1)
+        name = parts[0]
+        if len(parts) > 1:
+            value = self._path(parts[1])
+        else:
+            value = None
+        location = (self.filename, self.lineno)
+        return commands.FeatureCommand(name, value, location=location)
+
+
+    def _parse_file_modify(self, info):
+        """Parse a filemodify command within a commit.
+
+        :param info: a string in the format "mode dataref path"
+          (where dataref might be the hard-coded literal 'inline').
+        """
+        params = info.split(' ', 2)
+        path = self._path(params[2])
+        mode = params[0]
+        if params[1] == 'inline':
+            dataref = None
+            data = self._get_data('filemodify')
+        else:
+            dataref = params[1]
+            data = None
+        return commands.FileModifyCommand(path, mode, dataref, data)
+
+    def _parse_reset(self, ref):
+        """Parse a reset command."""
+        from_ = self._get_from()
+        return commands.ResetCommand(ref, from_)
+
+    def _parse_tag(self, name):
+        """Parse a tag command."""
+        from_ = self._get_from('tag')
+        tagger = self._get_user_info('tag', 'tagger', accept_just_who=True)
+        message = self._get_data('tag', 'message').decode('utf_8')
+        return commands.TagCommand(name, from_, tagger, message)
+
+    def _get_mark_if_any(self):
+        """Parse a mark section."""
+        line = self.next_line()
+        if line.startswith('mark :'):
+            return line[len('mark :'):]
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_from(self, required_for=None):
+        """Parse a from section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('from '):
+            return line[len('from '):]
+        elif required_for:
+            self.abort(errors.MissingSection, required_for, 'from')
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_merge(self):
+        """Parse a merge section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('merge '):
+            return line[len('merge '):]
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_property(self):
+        """Parse a property section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('property '):
+            return self._name_value(line[len('property '):])
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_user_info(self, cmd, section, required=True,
+        accept_just_who=False):
+        """Parse a user section."""
+        line = self.next_line()
+        if line.startswith(section + ' '):
+            return self._who_when(line[len(section + ' '):], cmd, section,
+                accept_just_who=accept_just_who)
+        elif required:
+            self.abort(errors.MissingSection, cmd, section)
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_data(self, required_for, section='data'):
+        """Parse a data section."""
+        line = self.next_line()
+        if line.startswith('data '):
+            rest = line[len('data '):]
+            if rest.startswith('<<'):
+                return self.read_until(rest[2:])
+            else:
+                size = int(rest)
+                read_bytes = self.read_bytes(size)
+                # optional LF after data.
+                next = self.input.readline()
+                self.lineno += 1
+                if len(next) > 1 or next != "\n":
+                    self.push_line(next[:-1])
+                return read_bytes
+        else:
+            self.abort(errors.MissingSection, required_for, section)
+
+    def _who_when(self, s, cmd, section, accept_just_who=False):
+        """Parse who and when information from a string.
+        
+        :return: a tuple of (name,email,timestamp,timezone). name may be
+            the empty string if only an email address was given.
+        """
+        match = _WHO_AND_WHEN_RE.search(s)
+        if match:
+            datestr = match.group(3)
+            if self.date_parser is None:
+                # auto-detect the date format
+                if len(datestr.split(' ')) == 2:
+                    format = 'raw'
+                elif datestr == 'now':
+                    format = 'now'
+                else:
+                    format = 'rfc2822'
+                self.date_parser = dates.DATE_PARSERS_BY_NAME[format]
+            when = self.date_parser(datestr, self.lineno)
+        else:
+            match = _WHO_RE.search(s)
+            if accept_just_who and match:
+                # HACK around missing time
+                # TODO: output a warning here
+                when = dates.DATE_PARSERS_BY_NAME['now']('now')
+            else:
+                self.abort(errors.BadFormat, cmd, section, s)
+
+        # Do not attempt to decode name or email address; they are just
+        # bytes.  (Everything will work out better if they are in UTF-8,
+        # but that's not guaranteed.)
+        name = match.group(1).rstrip()
+        email = match.group(2)
+        return (name, email, when[0], when[1])
+
+    def _name_value(self, s):
+        """Parse a (name,value) tuple from 'name value-length value'."""
+        parts = s.split(' ', 2)
+        name = parts[0]
+        if len(parts) == 1:
+            value = None
+        else:
+            size = int(parts[1])
+            value = parts[2]
+            still_to_read = size - len(value)
+            if still_to_read == 1:
+                value += "\n"
+            elif still_to_read > 0:
+                read_bytes = self.read_bytes(still_to_read - 1)
+                value += "\n" + read_bytes
+            value = value.decode('utf8')
+        return (name, value)
+
+    def _path(self, s):
+        """Parse a path."""
+        if s.startswith('"'):
+            if s[-1] != '"':
+                self.abort(errors.BadFormat, '?', '?', s)
+            else:
+                return _unquote_c_string(s[1:-1])
+
+        # Do *not* decode the path to a Unicode string: filenames on
+        # Unix are just bytes.  Git and Mercurial, at least, inherit
+        # this stance.  git-fast-import(1) merely says "It is
+        # recommended that  always be encoded using UTF-8.", which
+        # is good advice ... but not something we can count on here.
+        return s
+
+    def _path_pair(self, s):
+        """Parse two paths separated by a space."""
+        # TODO: handle a space in the first path
+        if s.startswith('"'):
+            parts = s[1:].split('" ', 1)
+        else:
+            parts = s.split(' ', 1)
+        if len(parts) != 2:
+            self.abort(errors.BadFormat, '?', '?', s)
+        elif parts[1].startswith('"') and parts[1].endswith('"'):
+            parts[1] = parts[1][1:-1]
+        elif parts[1].startswith('"') or parts[1].endswith('"'):
+            self.abort(errors.BadFormat, '?', '?', s)
+        return map(_unquote_c_string, parts)
+
+    def _mode(self, s):
+        """Parse a file mode into executable and symlink flags.
+        
+        :return (is_executable, is_symlink)
+        """
+        # Note: Output from git-fast-export slightly different to spec
+        if s in ['644', '100644', '0100644']:
+            return False, False
+        elif s in ['755', '100755', '0100755']:
+            return True, False
+        elif s in ['120000', '0120000']:
+            return False, True
+        else:
+            self.abort(errors.BadFormat, 'filemodify', 'mode', s)
+
+
+def _unquote_c_string(s):
+    """replace C-style escape sequences (\n, \", etc.) with real chars."""
+    # HACK: Python strings are close enough
+    return s.decode('string_escape', 'replace')
diff --git a/git_remote_helpers/fastimport/processor.py b/git_remote_helpers/fastimport/processor.py
new file mode 100644
index 0000000000..bfb4226a46
--- /dev/null
+++ b/git_remote_helpers/fastimport/processor.py
@@ -0,0 +1,222 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Processor of import commands.
+
+This module provides core processing functionality including an abstract class
+for basing real processors on. See the processors package for examples.
+"""
+
+import sys
+import time
+import logging
+
+from git_remote_helpers.fastimport import errors
+
+log = logging.getLogger(__name__)
+
+
+class ImportProcessor(object):
+    """Base class for import processors.
+    
+    Subclasses should override the pre_*, post_* and *_handler
+    methods as appropriate.
+    """
+
+    known_params = []
+
+    def __init__(self, params=None, verbose=False, outf=None):
+        if outf is None:
+            self.outf = sys.stdout
+        else:
+            self.outf = outf
+        self.verbose = verbose
+        if params is None:
+            self.params = {}
+        else:
+            self.params = params
+            self.validate_parameters()
+
+        # Handlers can set this to request exiting cleanly without
+        # iterating through the remaining commands
+        self.finished = False
+
+    def validate_parameters(self):
+        """Validate that the parameters are correctly specified."""
+        for p in self.params:
+            if p not in self.known_params:
+                raise errors.UnknownParameter(p, self.known_params)
+
+    def process(self, commands):
+        """Process a stream of fast-import commands from a parser.
+
+        :param commands: a sequence of commands.ImportCommand objects
+        """
+        self.pre_process()
+        for cmd in commands:
+            try:
+                handler = self.__class__.__dict__[cmd.name + "_handler"]
+            except KeyError:
+                raise errors.MissingHandler(cmd.name)
+            else:
+                self.pre_handler(cmd)
+                handler(self, cmd)
+                self.post_handler(cmd)
+            if self.finished:
+                break
+        self.post_process()
+
+    def pre_process(self):
+        """Hook for logic at start of processing.
+
+        Called just before process() starts iterating over its sequence
+        of commands.
+        """
+        pass
+
+    def post_process(self):
+        """Hook for logic at end of successful processing.
+
+        Called after process() finishes successfully iterating over its
+        sequence of commands (i.e. not called if an exception is raised
+        while processing commands).
+        """
+        pass
+
+    def pre_handler(self, cmd):
+        """Hook for logic before each handler starts."""
+        pass
+
+    def post_handler(self, cmd):
+        """Hook for logic after each handler finishes."""
+        pass
+
+    def progress_handler(self, cmd):
+        """Process a ProgressCommand."""
+        raise NotImplementedError(self.progress_handler)
+
+    def blob_handler(self, cmd):
+        """Process a BlobCommand."""
+        raise NotImplementedError(self.blob_handler)
+
+    def checkpoint_handler(self, cmd):
+        """Process a CheckpointCommand."""
+        raise NotImplementedError(self.checkpoint_handler)
+
+    def commit_handler(self, cmd):
+        """Process a CommitCommand."""
+        raise NotImplementedError(self.commit_handler)
+
+    def reset_handler(self, cmd):
+        """Process a ResetCommand."""
+        raise NotImplementedError(self.reset_handler)
+
+    def tag_handler(self, cmd):
+        """Process a TagCommand."""
+        raise NotImplementedError(self.tag_handler)
+
+    def feature_handler(self, cmd):
+        """Process a FeatureCommand."""
+        raise NotImplementedError(self.feature_handler)
+
+
+class CommitHandler(object):
+    """Base class for commit handling.
+    
+    Subclasses should override the pre_*, post_* and *_handler
+    methods as appropriate.
+    """
+
+    def __init__(self, command):
+        self.command = command
+
+    def process(self):
+        self.pre_process_files()
+        for fc in self.command.file_cmds:
+            try:
+                handler = self.__class__.__dict__[fc.name[4:] + "_handler"]
+            except KeyError:
+                raise errors.MissingHandler(fc.name)
+            else:
+                handler(self, fc)
+        self.post_process_files()
+
+    def _log(self, level, msg, *args):
+        log.log(level, msg + " (%s)", *(args + (self.command.id,)))
+
+    # Logging methods: unused in this library, but used by
+    # bzr-fastimport.  Could be useful for other subclasses.
+
+    def note(self, msg, *args):
+        """log.info() with context about the command"""
+        self._log(logging.INFO, msg, *args)
+
+    def warning(self, msg, *args):
+        """log.warning() with context about the command"""
+        self._log(logging.WARNING, msg, *args)
+
+    def debug(self, msg, *args):
+        """log.debug() with context about the command"""
+        self._log(logging.DEBUG, msg, *args)
+
+    def pre_process_files(self):
+        """Prepare for committing."""
+        pass
+
+    def post_process_files(self):
+        """Save the revision."""
+        pass
+
+    def modify_handler(self, filecmd):
+        """Handle a filemodify command."""
+        raise NotImplementedError(self.modify_handler)
+
+    def delete_handler(self, filecmd):
+        """Handle a filedelete command."""
+        raise NotImplementedError(self.delete_handler)
+
+    def copy_handler(self, filecmd):
+        """Handle a filecopy command."""
+        raise NotImplementedError(self.copy_handler)
+
+    def rename_handler(self, filecmd):
+        """Handle a filerename command."""
+        raise NotImplementedError(self.rename_handler)
+
+    def deleteall_handler(self, filecmd):
+        """Handle a filedeleteall command."""
+        raise NotImplementedError(self.deleteall_handler)
+
+
+def parseMany(filenames, parser_factory, processor):
+    """Parse multiple input files, sending the results all to
+    'processor'.  parser_factory must be a callable that takes one input
+    file and returns an ImportParser instance, e.g. the ImportParser
+    class object itself.  Each file in 'filenames' is opened, parsed,
+    and closed in turn.  For filename \"-\", reads stdin.
+    """
+    for filename in filenames:
+        if filename == "-":
+            infile = sys.stdin
+        else:
+            infile = open(filename, "rb")
+
+        try:
+            parser = parser_factory(infile)
+            processor.process(parser.parse())
+        finally:
+            if filename != "-":
+                infile.close()
diff --git a/git_remote_helpers/setup.py b/git_remote_helpers/setup.py
index 4d434b65cb..a19c061fdf 100644
--- a/git_remote_helpers/setup.py
+++ b/git_remote_helpers/setup.py
@@ -13,5 +13,6 @@ setup(
     author_email = 'git@vger.kernel.org',
     url = 'http://www.git-scm.com/',
     package_dir = {'git_remote_helpers': ''},
-    packages = ['git_remote_helpers', 'git_remote_helpers.git'],
+    packages = ['git_remote_helpers', 'git_remote_helpers.git',
+                'git_remote_helpers.fastimport'],
 )

From e1096003dc41b2cc6da49b21f8096a614ea844f8 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:05:53 +0200
Subject: [PATCH 3568/3720] git-remote-hg: add hgimport, an hg-fast-import
 equivalent

This class will be used by git-remote-hg to do the heavy lifting.
---
 git_remote_helpers/hg/hgimport.py | 401 ++++++++++++++++++++++++++++++
 1 file changed, 401 insertions(+)
 create mode 100644 git_remote_helpers/hg/hgimport.py

diff --git a/git_remote_helpers/hg/hgimport.py b/git_remote_helpers/hg/hgimport.py
new file mode 100644
index 0000000000..36fee8e96b
--- /dev/null
+++ b/git_remote_helpers/hg/hgimport.py
@@ -0,0 +1,401 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Processor of import commands.
+
+This module provides core processing functionality including an abstract class
+for basing real processors on. See the processors package for examples.
+"""
+
+import os
+import shutil
+
+from mercurial import context
+from mercurial.node import nullid, hex
+
+from git_remote_helpers.util import die
+from git_remote_helpers.fastimport import processor, parser
+
+
+class commit(object):
+    def __init__(self, author, date, desc, parents, branch=None, rev=None,
+                 extra={}, sortkey=None):
+        self.author = author or 'unknown'
+        self.date = date or '0 0'
+        self.desc = desc
+        self.parents = parents
+        self.branch = branch
+        self.rev = rev
+        self.extra = extra
+        self.sortkey = sortkey
+
+
+class HgImportProcessor(processor.ImportProcessor):
+
+    def __init__(self, ui, repo):
+        super(HgImportProcessor, self).__init__()
+        self.ui = ui
+        self.repo = repo
+
+        self.branchnames = True
+
+        self.idmap = {}
+        self.commitmap = {}             # map commit ID (":1") to commit object
+        self.branchmap = {}             # map branch name to list of heads
+
+        self.tags = []                  # list of (tag, mark) tuples
+
+        self.numblobs = 0               # for progress reporting
+        self.blobdir = None
+
+    def setup(self):
+        """Setup before processing any streams."""
+        pass
+
+    def teardown(self):
+        """Cleanup after processing all streams."""
+        if self.blobdir and os.path.exists(self.blobdir):
+            self.ui.status("Removing blob dir %r ...\n" % self.blobdir)
+            shutil.rmtree(self.blobdir)
+
+    def load_marksfile(self, name):
+        try:
+            f = open(name)
+            lines = f.readlines()
+            f.close()
+            parsed = [i.strip().split(' ') for i in lines]
+            self.idmap = dict((i[0], i[1]) for i in parsed)
+        except IOError, e:
+            die("load: %s", str(e))
+
+    def write_marksfile(self, name):
+        try:
+            f = open(name, "w")
+            for pair in sorted(self.idmap.iteritems()):
+                f.write("%s %s\n" % pair)
+            f.close()
+        except IOError, e:
+            die("write: %s", str(e))
+
+    def progress_handler(self, cmd):
+        self.ui.write("Progress: %s\n" % cmd.message)
+
+    def blob_handler(self, cmd):
+        self.writeblob(cmd.id, cmd.data)
+
+    def _getblobfilename(self, blobid):
+        if self.blobdir is None:
+            raise RuntimeError("no blobs seen, so no blob directory created")
+        # XXX should escape ":" for windows
+        return os.path.join(self.blobdir, "blob-" + blobid)
+
+    def getblob(self, fileid):
+        (commitid, blobid) = fileid
+        f = open(self._getblobfilename(blobid), "rb")
+        try:
+            return f.read()
+        finally:
+            f.close()
+
+    def writeblob(self, blobid, data):
+        if self.blobdir is None:        # no blobs seen yet
+            self.blobdir = os.path.join(self.repo.root, ".hg", "blobs")
+            if not os.path.exists(self.blobdir):
+                os.mkdir(self.blobdir)
+
+        fn = self._getblobfilename(blobid)
+        blobfile = open(fn, "wb")
+        #self.ui.debug("writing blob %s to %s (%d bytes)\n"
+        #              % (blobid, fn, len(data)))
+        blobfile.write(data)
+        blobfile.close()
+
+        self.numblobs += 1
+        if self.numblobs % 500 == 0:
+            self.ui.status("%d blobs read\n" % self.numblobs)
+
+    def getmode(self, name, fileid):
+        (commitid, blobid) = fileid
+        return self.filemodes[commitid][name]
+
+    def checkpoint_handler(self, cmd):
+        # This command means nothing to us
+        pass
+
+    def _getcommit(self, committish):
+        """Given a mark reference or a branch name, return the
+        appropriate commit object.  Return None if committish is a
+        branch with no commits.  Raises KeyError if anything else is out
+        of whack.
+        """
+        if committish.startswith(":"):
+            # KeyError here indicates the input stream is broken.
+            return self.commitmap[committish]
+        else:
+            branch = self._getbranch(committish)
+            if branch is None:
+                raise ValueError("invalid committish: %r" % committish)
+
+            heads = self.branchmap.get(branch)
+            if heads is None:
+                return None
+            else:
+                # KeyError here indicates bad commit id in self.branchmap.
+                return self.commitmap[heads[-1]]
+
+    def _getbranch(self, ref):
+        """Translate a Git head ref to corresponding Mercurial branch
+        name.  E.g. \"refs/heads/foo\" is translated to \"foo\".
+        Special case: \"refs/heads/master\" becomes \"default\".  If
+        'ref' is not a head ref, return None.
+        """
+        prefix = "refs/heads/"
+        if ref.startswith(prefix):
+            branch = ref[len(prefix):]
+            if branch == "master":
+                return "default"
+            else:
+                return branch
+        else:
+            return None
+
+    def commit_handler(self, cmd):
+        # XXX this assumes the fixup branch name used by cvs2git.  In
+        # contrast, git-fast-import(1) recommends "TAG_FIXUP" (not under
+        # refs/heads), and implies that it can be called whatever the
+        # creator of the fastimport dump wants to call it.  So the name
+        # of the fixup branch should be configurable!
+        fixup = (cmd.ref == "refs/heads/TAG.FIXUP")
+
+        if cmd.from_:
+            first_parent = cmd.from_
+        else:
+            first_parent = self._getcommit(cmd.ref) # commit object
+            if first_parent is not None:
+                first_parent = first_parent.rev     # commit id
+
+        if cmd.merges:
+            if len(cmd.merges) > 1:
+                raise NotImplementedError("Can't handle more than two parents")
+            second_parent = cmd.merges[0]
+        else:
+            second_parent = None
+
+        if first_parent is None and second_parent is not None:
+            # First commit on a new branch that has 'merge' but no 'from':
+            # special case meaning branch starts with no files; the contents of
+            # the first commit (this one) determine the list of files at branch
+            # time.
+            first_parent = second_parent
+            second_parent = None
+            no_files = True             # XXX this is ignored...
+
+        self.ui.debug("commit %s: first_parent = %r, second_parent = %r\n"
+                      % (cmd, first_parent, second_parent))
+        assert ((first_parent != second_parent) or
+                (first_parent is second_parent is None)), \
+               ("commit %s: first_parent == second parent = %r"
+                % (cmd, first_parent))
+
+        # Figure out the Mercurial branch name.
+        if fixup and first_parent is not None:
+            # If this is a fixup commit, pretend it happened on the same
+            # branch as its first parent.  (We don't want a Mercurial
+            # named branch called "TAG.FIXUP" in the output repository.)
+            branch = self.commitmap[first_parent].branch
+        else:
+            branch = self._getbranch(cmd.ref)
+
+        commit_handler = HgImportCommitHandler(
+            self, cmd, self.ui)
+        commit_handler.process()
+        modified = dict(commit_handler.modified)
+        modes = commit_handler.mode
+        copies = commit_handler.copies
+
+        # in case we are converting from git or bzr, prefer author but
+        # fallback to committer (committer is required, author is
+        # optional)
+        userinfo = cmd.author or cmd.committer
+        if userinfo[0] == userinfo[1]:
+            # In order to conform to fastimport syntax, cvs2git with no
+            # authormap produces author names like "jsmith "; if
+            # we see that, revert to plain old "jsmith".
+            user = userinfo[0]
+        else:
+            user = "%s <%s>" % (userinfo[0], userinfo[1])
+
+        assert type(cmd.message) is unicode
+        text = cmd.message.encode("utf-8")
+        date = self.convert_date(userinfo)
+
+        parents = [self.idmap[i] for i in first_parent, second_parent if i]
+        cmt = commit(user, date, text, parents, branch, rev=cmd.id)
+
+        self.commitmap[cmd.id] = cmt
+        heads = self.branchmap.get(branch)
+        if heads is None:
+            heads = [cmd.id]
+        else:
+            # adding to an existing branch: replace the previous head
+            try:
+                heads.remove(first_parent)
+            except ValueError:          # first parent not a head: no problem
+                pass
+            heads.append(cmd.id)        # at end means this is tipmost
+        self.branchmap[branch] = heads
+        self.ui.debug("processed commit %s\n" % cmd)
+
+        self.idmap[cmd.id] = self.putcommit(modified, modes, copies, cmt)
+
+    def putcommit(self, files, modes, copies, commit):
+
+        def getfilectx(repo, memctx, name):
+            fileid = files[name]
+            if fileid is None:  # deleted file
+                raise IOError
+            data = self.getblob(fileid)
+            ctx = context.memfilectx(name, data, 'l' in modes,
+                                     'x' in modes, copies.get(name))
+            return ctx
+
+        parents = list(set(commit.parents))
+        nparents = len(parents)
+
+        if len(parents) < 2:
+            parents.append(nullid)
+        if len(parents) < 2:
+            parents.append(nullid)
+        p2 = parents.pop(0)
+
+        text = commit.desc
+        extra = commit.extra.copy()
+        if self.branchnames and commit.branch:
+            extra['branch'] = commit.branch
+
+        while parents:
+            p1 = p2
+            p2 = parents.pop(0)
+            ctx = context.memctx(self.repo, (p1, p2), text, files.keys(),
+                                 getfilectx, commit.author, commit.date, extra)
+            self.repo.commitctx(ctx)
+            text = "(octopus merge fixup)\n"
+            p2 = hex(self.repo.changelog.tip())
+
+        return p2
+
+    def convert_date(self, c):
+        res = (int(c[2]), int(c[3]))
+        #print c, res
+        #print type((0, 0)), type(res), len(res), type(res) is type((0, 0))
+        #if type(res) is type((0, 0)) and len(res) == 2:
+        #    print "go for it"
+        #return res
+        return "%d %d" % res
+
+    def reset_handler(self, cmd):
+        tagprefix = "refs/tags/"
+        branch = self._getbranch(cmd.ref)
+        if branch:
+            # The usual case for 'reset': (re)create the named branch.
+            # XXX what should we do if cmd.from_ is None?
+            if cmd.from_ is not None:
+                self.branchmap[branch] = [cmd.from_]
+            else:
+                # pretend the branch never existed... is this right?!?
+                try:
+                    del self.branchmap[branch]
+                except KeyError:
+                    pass
+            #else:
+            #    # XXX filename? line number?
+            #    self.ui.warn("ignoring branch reset with no 'from'\n")
+        elif cmd.ref.startswith(tagprefix):
+            # Create a "lightweight tag" in Git terms.  As I understand
+            # it, that's a tag with no description and no history --
+            # rather like CVS tags.  cvs2git turns CVS tags into Git
+            # lightweight tags, so we should make sure they become
+            # Mercurial tags.  But we don't have to fake a history for
+            # them; save them up for the end.
+            tag = cmd.ref[len(tagprefix):]
+            self.tags.append((tag, cmd.from_))
+
+    def tag_handler(self, cmd):
+        pass
+
+    def feature_handler(self, cmd):
+        if cmd.feature_name == 'done':
+            return
+        raise NotImplementedError(self.feature_handler)
+
+
+class HgImportCommitHandler(processor.CommitHandler):
+
+    def __init__(self, parent, command, ui):
+        self.parent = parent            # HgImportProcessor running the show
+        self.command = command          # CommitCommand that we're processing
+        self.ui = ui
+
+        # Files changes by this commit as a list of (filename, id)
+        # tuples where id is (commitid, blobid).  The blobid is
+        # needed to fetch the file's contents later, and the commitid
+        # is needed to fetch the mode.
+        # (XXX what about inline file contents?)
+        # (XXX how to describe deleted files?)
+        self.modified = []
+
+        # mode of files listed in self.modified: '', 'x', or 'l'
+        self.mode = {}
+
+        # dictionary of src: dest (renamed files are in here and self.modified)
+        self.copies = {}
+
+        # number of inline files seen in this commit
+        self.inlinecount = 0
+
+    def modify_handler(self, filecmd):
+        if filecmd.dataref:
+            blobid = filecmd.dataref    # blobid is the mark of the blob
+        else:
+            blobid = "%s-inline:%d" % (self.command.id, self.inlinecount)
+            assert filecmd.data is not None
+            self.parent.writeblob(blobid, filecmd.data)
+            self.inlinecount += 1
+
+        fileid = (self.command.id, blobid)
+
+        self.modified.append((filecmd.path, fileid))
+        if filecmd.mode.endswith("644"): # normal file
+            mode = ''
+        elif filecmd.mode.endswith("755"): # executable
+            mode = 'x'
+        elif filecmd.mode == "120000":  # symlink
+            mode = 'l'
+        else:
+            raise RuntimeError("mode %r unsupported" % filecmd.mode)
+
+        self.mode[filecmd.path] = mode
+
+    def delete_handler(self, filecmd):
+        self.modified.append((filecmd.path, None))
+
+    def copy_handler(self, filecmd):
+        self.copies[filecmd.src_path] = filecmd.dest_path
+
+    def rename_handler(self, filecmd):
+        # copy oldname to newname and delete oldname
+        self.copies[filecmd.oldname] = filecmd.newname
+        self.files.append((filecmd.path, None))

From af48b93b72738192d0192c4aeef9a7e7c7fa6e14 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:12:27 +0200
Subject: [PATCH 3569/3720] git-remote-hg: add GitHg, a helper class for
 converting hg commits to git

This class will be used by HgExport.
---
 git_remote_helpers/hg/hg.py | 116 ++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 git_remote_helpers/hg/hg.py

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
new file mode 100644
index 0000000000..758ba242d8
--- /dev/null
+++ b/git_remote_helpers/hg/hg.py
@@ -0,0 +1,116 @@
+import urllib
+import re
+
+class GitHg(object):
+    """Class that handles various aspects of converting a hg commit to git.
+    """
+
+    def __init__(self, warn):
+        """Initializes a new GitHg object with the specified warner.
+        """
+
+        self.warn = warn
+
+    def format_timezone(self, offset):
+        if offset % 60 != 0:
+            raise ValueError("Unable to handle non-minute offset.")
+        sign = (offset < 0) and '-' or '+'
+        offset = abs(offset)
+        return '%c%02d%02d' % (sign, offset / 3600, (offset / 60) % 60)
+
+    def get_committer(self, ctx):
+        extra = ctx.extra()
+
+        if 'committer' in extra:
+            # fixup timezone
+            (name_timestamp, timezone) = extra['committer'].rsplit(' ', 1)
+            try:
+                timezone = self.format_timezone(-int(timezone))
+                return '%s %s' % (name_timestamp, timezone)
+            except ValueError:
+                self.warn("Ignoring committer in extra, invalid timezone in r%s: '%s'.\n" % (ctx.rev(), timezone))
+
+        return None
+
+    def get_message(self, ctx):
+        extra = ctx.extra()
+
+        message = ctx.description() + "\n"
+        if 'message' in extra:
+            message = apply_delta(message, extra['message'])
+
+        # HG EXTRA INFORMATION
+        add_extras = False
+        extra_message = ''
+        if not ctx.branch() == 'default':
+            add_extras = True
+            extra_message += "branch : " + ctx.branch() + "\n"
+
+        renames = []
+        for f in ctx.files():
+            if f not in ctx.manifest():
+                continue
+            rename = ctx.filectx(f).renamed()
+            if rename:
+                renames.append((rename[0], f))
+
+        if renames:
+            add_extras = True
+            for oldfile, newfile in renames:
+                extra_message += "rename : " + oldfile + " => " + newfile + "\n"
+
+        for key, value in extra.iteritems():
+            if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'):
+                continue
+            else:
+                add_extras = True
+                extra_message += "extra : " + key + " : " +  urllib.quote(value) + "\n"
+
+        if add_extras:
+            message += "\n--HG--\n" + extra_message
+
+        return message
+
+    def get_author(self, ctx):
+        # hg authors might not have emails
+        author = ctx.user()
+
+        # check for git author pattern compliance
+        regex = re.compile('^(.*?) \<(.*?)\>(.*)$')
+        a = regex.match(author)
+
+        if a:
+            name = a.group(1)
+            email = a.group(2)
+            if len(a.group(3)) > 0:
+                name += ' ext:(' + urllib.quote(a.group(3)) + ')'
+            author = name + ' <' + email + '>'
+        else:
+            author = author + ' '
+
+        if 'author' in ctx.extra():
+            author = apply_delta(author, ctx.extra()['author'])
+
+        (time, timezone) = ctx.date()
+        date = str(int(time)) + ' ' + self.format_timezone(-timezone)
+
+        return author + ' ' + date
+
+    def get_parents(self, ctx):
+        def is_octopus_part(ctx):
+            return ctx.extra().get('hg-git', None) in ('octopus', 'octopus-done')
+
+        parents = []
+        if ctx.extra().get('hg-git', None) == 'octopus-done':
+            # implode octopus parents
+            part = ctx
+            while is_octopus_part(part):
+                (p1, p2) = part.parents()
+                assert not is_octopus_part(p1)
+                parents.append(p1)
+                part = p2
+            parents.append(p2)
+        else:
+            parents = ctx.parents()
+
+        return parents

From e2cf0740725fa3fc2e3f0ce303d86f3424ae2824 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:37:06 +0200
Subject: [PATCH 3570/3720] git-remote-hg: add hgexport, an hg-fast-export
 equivalent

This class will be used by git-remote-hg to do the heavy lifting.
---
 git_remote_helpers/hg/hgexport.py | 280 ++++++++++++++++++++++++++++++
 1 file changed, 280 insertions(+)
 create mode 100644 git_remote_helpers/hg/hgexport.py

diff --git a/git_remote_helpers/hg/hgexport.py b/git_remote_helpers/hg/hgexport.py
new file mode 100644
index 0000000000..8a255a45d2
--- /dev/null
+++ b/git_remote_helpers/hg/hgexport.py
@@ -0,0 +1,280 @@
+import binascii
+import os.path
+import sys
+
+
+LF = '\n'
+SP = ' '
+
+
+class HgExportGenerator(object):
+    def __init__(self, repo):
+        self.git_hg = repo.git_hg
+        self.repo = repo
+        self.prefix = repo.prefix
+        self.nullref = "0" * 40
+        self.next_id = 0
+        self.mapping = {}
+        self.debugging = True
+
+    def nextid(self):
+        self.next_id += 1
+        return self.next_id
+
+    def tohex(self, binhex):
+        return binascii.hexlify(binhex)
+
+    def mode(self, fctx):
+        flags = fctx.flags()
+
+        if 'l' in flags:
+          mode = '120000'
+        elif 'x' in flags:
+          mode = '100755'
+        else:
+          mode = '100644'
+
+        return mode
+
+    def parents(self, parents):
+        parents = [self.tohex(i.node()) for i in parents]
+        parents = [i for i in parents if i != self.nullref]
+        assert all(i in self.mapping for i in parents)
+        parents = [':%d' % self.mapping[i] for i in parents]
+
+        return parents
+
+    def ref(self, ctx):
+        return self.prefix + ctx.branch()
+
+    def write(self, *args):
+        msg = ''.join([str(i) for i in args])
+        sys.stdout.write(msg)
+
+    def debug(self, msg):
+        assert LF not in msg
+        self.write('#', SP, msg, LF)
+
+    def feature(self, feature, value=None):
+        if value:
+            self.write('feature', SP, feature, '=', value, LF)
+        else:
+            self.write('feature', SP, feature, LF)
+
+    def option(self, option, value=None):
+        if value:
+            self.write('option', SP, option, '=', value, LF)
+        else:
+            self.write('option', SP, option, LF)
+
+    def option_quiet(self):
+        self.option('quiet')
+
+    def feature_relative_marks(self):
+        self.feature('relative-marks')
+
+    def feature_export_marks(self, marks):
+        self.feature('export-marks', marks)
+
+    def feature_import_marks(self, marks):
+        self.feature('import-marks', marks)
+
+    def feature_force(self):
+        self.feature('force')
+
+    def progress(self, message):
+        self.write('progress', SP, message, LF)
+
+    def write_data(self, data):
+        count = len(data)
+        self.write('data', SP, count, LF)
+        self.write(data, LF)
+
+    def write_mark(self, idnum):
+        self.write('mark', SP, ':', idnum, LF)
+
+    def write_blob(self, data, idnum):
+        self.write('blob', LF)
+        self.write_mark(idnum)
+        self.write_data(data)
+
+    def write_file(self, ctx, file, idnum):
+        fctx = ctx.filectx(file)
+        data = fctx.data()
+
+        self.write_blob(data, idnum)
+
+    def write_commit(self, ref):
+        self.write('commit', SP, ref, LF)
+
+    def write_author(self, author):
+        self.write('author', SP, author, LF)
+
+    def write_committer(self, committer):
+        self.write('committer', SP, committer, LF)
+
+    def write_from(self, parent):
+        self.write('from', SP, parent, LF)
+
+    def write_merge(self, parent):
+        self.write('merge', SP, parent, LF)
+
+    def write_reset(self, ref, idnum):
+        self.write('reset', SP, ref, LF)
+        self.write('from', SP, ':', idnum, LF)
+
+    def write_parents(self, parents):
+        parents = self.parents(parents)
+
+        # first commit
+        if not parents:
+            return
+
+        parent = parents[0]
+
+        self.write_from(parent)
+
+        for parent in parents[1:]:
+            self.write_merge(parent)
+
+    def write_filedeleteall(self):
+        self.write('deleteall', LF)
+
+    def write_filedelete(self, ctx, name):
+        self.write('D', SP, name, LF)
+
+    def write_filemodify_mark(self, mode, name, mark):
+        self.write('M', SP, mode, SP, ':', mark, SP, name, LF)
+
+    def write_filemodify_inline(self, mode, name, data):
+        self.write('M', SP, mode, SP, 'inline', SP, name, LF)
+        self.write_data(data)
+
+    def write_filemodify(self, ctx, name):
+        fctx = ctx.filectx(name)
+        man = ctx.manifest()
+        nodesha = man[name]
+        hash = self.tohex(nodesha)
+        mode = self.mode(fctx)
+
+        if hash in self.mapping:
+            mark = self.mapping[hash]
+            self.write_filemodify_mark(mode, name, mark)
+        else:
+            data = fctx.data()
+            self.write_filemodify_inline(mode, name, data)
+
+    def write_files(self, ctx):
+        man = ctx.manifest()
+
+        if len(ctx.parents()) == 2:
+            self.write_filedeleteall()
+            for name in man:
+                self.write_filemodify(ctx, name)
+        else:
+            for name in ctx.files():
+                # file got deleted
+                if name not in man:
+                    self.write_filedelete(ctx, name)
+                else:
+                    self.write_filemodify(ctx, name)
+
+    def export_files(self, ctx):
+        man = ctx.manifest()
+
+        for name in [i for i in ctx.files() if i in man]:
+            idnum = self.nextid()
+            nodesha = man[name]
+            hash = self.tohex(nodesha)
+
+            self.write_file(ctx, name, idnum)
+            self.mapping[hash] = idnum
+
+    def export_commit(self, ctx, ref, idnum, msg, parents):
+        author = self.git_hg.get_author(ctx)
+        committer = self.git_hg.get_committer(ctx)
+        committer = committer if committer else author
+
+        self.debug('exporting commit')
+        self.write_commit(ref)
+        self.write_mark(idnum)
+        self.write_author(author)
+        self.write_committer(committer)
+        self.write_data(msg)
+        self.write_parents(parents)
+        self.write_files(ctx)
+        self.debug('commit exported')
+
+    def export_revision(self, ctx):
+        nodesha = ctx.node()
+        hash = self.tohex(nodesha)
+
+        if hash in self.mapping:
+            return False
+
+        self.export_files(ctx)
+
+        idnum = self.nextid()
+
+        ref = self.ref(ctx)
+        msg = self.git_hg.get_message(ctx)
+        parents = self.git_hg.get_parents(ctx)
+
+        self.export_commit(ctx, ref, idnum, msg, parents)
+        self.mapping[hash] = idnum
+
+        return True
+
+    def export_branch(self, name, rev):
+        ctx = self.repo.changectx(rev)
+        nodesha = ctx.node()
+        hash = self.tohex(nodesha)
+        idnum = self.mapping[hash]
+
+        ref = self.prefix + name
+
+        self.write_reset(ref, idnum)
+
+    def export_repo(self, refs):
+        self.option_quiet()
+        self.feature_force()
+
+        exported = printed = False
+
+        for rev in self.repo.changelog:
+            ctx = self.repo.changectx(rev)
+            exported = self.export_revision(ctx) or exported
+
+            if (exported and not printed) or (exported and rev%1000 == 0):
+                self.progress("Exported revision %d.\n" % rev)
+                printed = True
+
+    def write_marks(self, base):
+        dirname = self.repo.get_base_path(base)
+        path = os.path.join(dirname, 'hg.marks')
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+        f = open(path, 'w') #self.repo.opener(self.marksfile, 'w', atomictemp=True)
+
+        second = lambda (a, b): b
+
+        for hash, mark in sorted(self.mapping.iteritems(), key=second):
+            f.write(':%d %s\n' % (mark, hash))
+
+        f.close() #f.rename()
+
+    def read_marks(self, base):
+        dirname = self.repo.get_base_path(base)
+        path = os.path.join(dirname, 'hg.marks')
+
+        if not os.path.exists(path):
+            sys.stderr.write("warning: cannot find " + path)
+            return
+
+        f = open(path) #self.repo.opener(self.marksfile)
+
+        marks = [i.strip().split(' ') for i in f.readlines()]
+
+        self.mapping = dict((i[1], int(i[0][1:])) for i in marks)
+        self.next_id = max(self.mapping.values())
+

From 1add01b56f289375d1bfa53a7362138c3f0f2b62 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:38:43 +0200
Subject: [PATCH 3571/3720] git-remote-hg: add
 GitExporter/GitImporter/NonLocalGit

This is inftrastructure required to implement git-remote-hg.
---
 git_remote_helpers/hg/__init__.py  |  0
 git_remote_helpers/hg/exporter.py  | 29 +++++++++++++++++
 git_remote_helpers/hg/importer.py  | 29 +++++++++++++++++
 git_remote_helpers/hg/non_local.py | 51 ++++++++++++++++++++++++++++++
 git_remote_helpers/hg/util.py      | 14 ++++++++
 5 files changed, 123 insertions(+)
 create mode 100644 git_remote_helpers/hg/__init__.py
 create mode 100644 git_remote_helpers/hg/exporter.py
 create mode 100644 git_remote_helpers/hg/importer.py
 create mode 100644 git_remote_helpers/hg/non_local.py
 create mode 100644 git_remote_helpers/hg/util.py

diff --git a/git_remote_helpers/hg/__init__.py b/git_remote_helpers/hg/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/git_remote_helpers/hg/exporter.py b/git_remote_helpers/hg/exporter.py
new file mode 100644
index 0000000000..20b564dfc0
--- /dev/null
+++ b/git_remote_helpers/hg/exporter.py
@@ -0,0 +1,29 @@
+import binascii
+import os.path
+import sys
+
+from git_remote_helpers.hg import hgexport
+
+
+class GitExporter(object):
+    def __init__(self, repo):
+        self.repo = repo
+
+    def export_repo(self, base, refs):
+        gitmarksfile = os.path.join(self.repo.hash, 'git.marks')
+
+        exporter = hgexport.HgExportGenerator(self.repo)
+
+        exporter.feature_relative_marks()
+        exporter.feature_export_marks(gitmarksfile)
+
+        dirname = self.repo.get_base_path(base)
+        path = os.path.abspath(os.path.join(dirname, 'git.marks'))
+
+        if os.path.exists(path):
+            exporter.feature_import_marks(gitmarksfile)
+            exporter.read_marks(base)
+
+        exporter.export_repo(refs)
+
+        exporter.write_marks(base)
diff --git a/git_remote_helpers/hg/importer.py b/git_remote_helpers/hg/importer.py
new file mode 100644
index 0000000000..ff1eabda02
--- /dev/null
+++ b/git_remote_helpers/hg/importer.py
@@ -0,0 +1,29 @@
+import os.path
+import sys
+
+from git_remote_helpers.hg import hgimport
+from git_remote_helpers.fastimport import processor, parser
+
+
+class GitImporter(object):
+    def __init__(self, repo):
+        self.repo = repo
+
+    def do_import(self, base):
+        sources = ["-"]
+
+        dirname = self.repo.get_base_path(base)
+
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+
+        procc = hgimport.HgImportProcessor(self.repo.ui, self.repo)
+
+        marks_file = os.path.abspath(os.path.join(dirname, 'hg.marks'))
+
+        if os.path.exists(marks_file):
+            procc.load_marksfile(marks_file)
+
+        processor.parseMany(sources, parser.ImportParser, procc)
+
+        procc.write_marksfile(marks_file)
diff --git a/git_remote_helpers/hg/non_local.py b/git_remote_helpers/hg/non_local.py
new file mode 100644
index 0000000000..715bd68cd4
--- /dev/null
+++ b/git_remote_helpers/hg/non_local.py
@@ -0,0 +1,51 @@
+import os
+
+from git_remote_helpers.util import die, warn
+
+class NonLocalHg(object):
+    def __init__(self, repo):
+        self.repo = repo
+        self.hg = repo.hg
+
+    def clone(self, base):
+        path = self.repo.get_base_path(base)
+
+        # already cloned
+        if os.path.exists(os.path.join(path, '.hg')):
+            return path
+
+        if not os.path.exists(path):
+            os.makedirs(path)
+
+        if self.repo.path.endswith(".hg"):
+            from_path = self.repo.path[:-3]
+        else:
+            from_path = self.repo.path
+
+        self.repo.ui.setconfig('ui', 'quiet', "true")
+        self.hg.clone(self.repo.ui, from_path, path, update=False, pull=True)
+
+        return path
+
+    def update(self, base):
+        path = self.repo.get_base_path(base)
+
+        if not os.path.exists(path):
+            die("could not find repo at %s", path)
+
+        repo = self.hg.repository(self.repo.ui, path)
+
+        repo.ui.setconfig('ui', 'quiet', "true")
+        repo.pull(self.repo, heads=self.repo.heads(), force=True)
+
+    def push(self, base):
+        path = self.repo.get_base_path(base)
+
+        if not os.path.exists(path):
+            die("could not find repo at %s", path)
+
+        repo = self.hg.repository(self.repo.ui, path)
+
+        self.repo.ui.setconfig('ui', 'quiet', "true")
+        repo.ui.setconfig('ui', 'quiet', "true")
+        repo.push(self.repo, force=False)
diff --git a/git_remote_helpers/hg/util.py b/git_remote_helpers/hg/util.py
new file mode 100644
index 0000000000..2cd54c1ad0
--- /dev/null
+++ b/git_remote_helpers/hg/util.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+from mercurial import hg
+
+def parseurl(url, heads=[]):
+    url, heads = hg.parseurl(url, heads)
+    if isinstance(heads, tuple) and len(heads) == 2:
+        # hg 1.6 or later
+        _junk, heads = heads
+    if heads:
+        checkout = heads[0]
+    else:
+        checkout = None
+    return url, heads, checkout

From 6d4bb42b5a2ef79b5d54a5a26cf7522d8ae2acb2 Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Fri, 16 Mar 2012 15:54:33 +0100
Subject: [PATCH 3572/3720] remote-hg: adjust to hg 1.9

hg 1.0 changed the signature of hg.clone(). Adjust to it.

A real fix would need to check the hg version or try/catch.
---
 git_remote_helpers/hg/non_local.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/non_local.py b/git_remote_helpers/hg/non_local.py
index 715bd68cd4..abb7908da0 100644
--- a/git_remote_helpers/hg/non_local.py
+++ b/git_remote_helpers/hg/non_local.py
@@ -23,7 +23,7 @@ class NonLocalHg(object):
             from_path = self.repo.path
 
         self.repo.ui.setconfig('ui', 'quiet', "true")
-        self.hg.clone(self.repo.ui, from_path, path, update=False, pull=True)
+        self.hg.clone(self.repo.ui, {}, from_path, path, update=False, pull=True)
 
         return path
 

From bed2af2abcfb573d1bcd1d042ec8e2fc3f0f391f Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:38:57 +0200
Subject: [PATCH 3573/3720] git-remote-hg: add the helper

The helper uses the previously added infrastructure.

Signed-off-by: Johannes Schindelin 
---
 .gitignore                  |   1 +
 Makefile                    |   1 +
 git-remote-hg.py            | 101 ++++++++++++++++++++++++++++++++++++
 git_remote_helpers/setup.py |   2 +-
 4 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 git-remote-hg.py

diff --git a/.gitignore b/.gitignore
index bf66648e2c..756356e19c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -121,6 +121,7 @@
 /git-remote-fd
 /git-remote-ext
 /git-remote-testgit
+/git-remote-hg
 /git-repack
 /git-replace
 /git-repo-config
diff --git a/Makefile b/Makefile
index 2b709e900e..e9b697a7e7 100644
--- a/Makefile
+++ b/Makefile
@@ -449,6 +449,7 @@ SCRIPT_PERL += git-send-email.perl
 SCRIPT_PERL += git-svn.perl
 
 SCRIPT_PYTHON += git-remote-testgit.py
+SCRIPT_PYTHON += git-remote-hg.py
 SCRIPT_PYTHON += git-p4.py
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
diff --git a/git-remote-hg.py b/git-remote-hg.py
new file mode 100644
index 0000000000..fdf61a737d
--- /dev/null
+++ b/git-remote-hg.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+import sys
+import os
+sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
+
+from git_remote_helpers.helper import RemoteHelper
+from git_remote_helpers.util import debug, die, warn
+from git_remote_helpers.hg import util
+from git_remote_helpers.hg.hg import GitHg
+from git_remote_helpers.hg.exporter import GitExporter
+from git_remote_helpers.hg.importer import GitImporter
+from git_remote_helpers.hg.non_local import NonLocalHg
+
+
+class HgRemoteHelper(RemoteHelper):
+    def get_repo(self, alias, url):
+        """Returns a hg.repository object initialized for usage.
+        """
+
+        try:
+            from mercurial import hg, ui
+        except ImportError:
+            die("Mercurial python libraries not installed")
+
+        remote = False
+
+        if url.startswith("remote://"):
+            remote = True
+            url = "file://%s" % url[9:]
+
+        ui = ui.ui()
+        source, revs, checkout = util.parseurl(ui.expandpath(url), ['default'])
+        repo = hg.repository(ui, source)
+        if repo.capable('branchmap'):
+            revs += repo.branchmap().keys()
+            revs = set(revs)
+
+        prefix = 'refs/hg/%s/' % alias
+        debug("prefix: '%s'", prefix)
+
+        repo.marksfile = 'git.marks'
+        repo.hg = hg
+        repo.prefix = prefix
+        repo.revs = revs
+
+        self.setup_repo(repo, alias)
+
+        repo.git_hg = GitHg(warn)
+        repo.exporter = GitExporter(repo)
+        repo.importer = GitImporter(repo)
+        repo.non_local = NonLocalHg(repo)
+
+        repo.is_local = not remote and repo.local()
+
+        return repo
+
+    def local_repo(self, repo, path):
+        """Returns a hg.repository object initalized for usage.
+        """
+
+        local = repo.hg.repository(repo.ui, path)
+
+        self.setup_local_repo(local, repo)
+
+        local.git_hg = repo.git_hg
+        local.hg = repo.hg
+        local.revs = repo.revs
+        local.exporter = GitExporter(local)
+        local.importer = GitImporter(local)
+        local.is_local = repo.is_local
+
+        return local
+
+    def do_list(self, repo, args):
+        """Lists all known references.
+        """
+
+        for ref in repo.revs:
+            debug("? refs/heads/%s", ref)
+            print "? refs/heads/%s" % ref
+
+        debug("@refs/heads/default HEAD")
+        print "@refs/heads/default HEAD"
+
+        print # end list
+
+    def sanitize(self, value):
+        """Cleans up the url.
+        """
+
+        if value.startswith('hg::'):
+            value = value[4:]
+
+        return value
+
+    def get_refs(self, repo, gitdir):
+        return repo.branchmap()
+
+if __name__ == '__main__':
+    sys.exit(HgRemoteHelper().main(sys.argv))
diff --git a/git_remote_helpers/setup.py b/git_remote_helpers/setup.py
index a19c061fdf..4799513c24 100644
--- a/git_remote_helpers/setup.py
+++ b/git_remote_helpers/setup.py
@@ -14,5 +14,5 @@ setup(
     url = 'http://www.git-scm.com/',
     package_dir = {'git_remote_helpers': ''},
     packages = ['git_remote_helpers', 'git_remote_helpers.git',
-                'git_remote_helpers.fastimport'],
+                'git_remote_helpers.fastimport', 'git_remote_helpers.hg'],
 )

From 953f6fb5bc717c323fb1c9b7762d85ae05bf64d5 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:39:03 +0200
Subject: [PATCH 3574/3720] git-remote-hg: add tests

---
 t/t5801-remote-hg.sh | 137 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 137 insertions(+)
 create mode 100755 t/t5801-remote-hg.sh

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
new file mode 100755
index 0000000000..18915ddb8c
--- /dev/null
+++ b/t/t5801-remote-hg.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Sverre Rabbelier
+#
+
+test_description='Test remote-helper import and export commands'
+
+. ./test-lib.sh
+
+if test_have_prereq PYTHON && "$PYTHON_PATH" -c '
+import sys
+if sys.hexversion < 0x02040000:
+    sys.exit(1)
+'
+then
+	:
+else
+	skip_all='skipping git remote-hg tests: requires Python 2.4 or newer'
+	test_done
+fi
+
+# Call cmp with the arguments -x ".hg" -x ".git"  
+
+vcs_cmp () {
+	$DIFF -u -x ".hg" -x ".git" $1 $2
+}
+
+ROOT=$PWD
+
+test_expect_success 'setup repository' '
+	printf "[ui]\nusername = A U Thor " > \
+		${HOME}/.hgrc &&
+	mkdir server &&
+	hg init server/.hg &&
+	hg clone "$ROOT/server" public &&
+	(cd public &&
+	 echo content >file &&
+	 hg add file &&
+	 hg commit -m one &&
+	 hg push)
+'
+
+test_expect_success 'cloning from local repo' '
+	git clone "hg::file://${ROOT}/server" localclone &&
+	vcs_cmp public localclone
+'
+
+test_expect_success 'cloning from remote repo' '
+	git clone "hg::remote://${ROOT}/server" clone &&
+	vcs_cmp public clone
+'
+
+test_expect_success 'create new commit on remote' '
+	(cd public &&
+	 echo content >>file &&
+	 hg commit -A -m two &&
+	 hg push)
+'
+
+test_expect_success 'pulling from local repo' '
+	(cd localclone && git pull) &&
+	vcs_cmp public localclone
+'
+
+test_expect_success 'pulling from remote remote' '
+	(cd clone && git pull) &&
+	vcs_cmp public clone
+'
+
+test_expect_success 'pushing to local empty repo' '
+	hg init localempty &&
+	(cd localclone &&
+	git push --all "hg::file://${ROOT}/localempty") &&
+	(cd localempty &&
+	hg up tip) &&
+	vcs_cmp localclone localempty
+'
+
+test_expect_success 'pushing to remote empty repo' '
+	hg init empty &&
+	(cd localclone &&
+	git push --all "hg::remote://${ROOT}/empty") &&
+	(cd empty &&
+	hg up tip) &&
+	vcs_cmp localclone empty
+'
+
+test_expect_success 'pushing to local repo' '
+	(cd localclone &&
+	echo content >>file &&
+	git commit -a -m three &&
+	git push) &&
+	(cd server &&
+	hg up tip) &&
+	vcs_cmp localclone server
+'
+
+test_expect_success 'synch with changes from localclone' '
+	(cd clone &&
+	 git pull)
+'
+
+test_expect_success 'pushing remote local repo' '
+	(cd clone &&
+	echo content >>file &&
+	git commit -a -m four &&
+	git push) &&
+	(cd server &&
+	hg up tip) &&
+	vcs_cmp clone server
+'
+
+test_expect_success 'creating new branch' '
+	(cd public &&
+	hg branch different-branch &&
+	echo different >> file &&
+	hg commit -m five &&
+	hg push -f)
+'
+
+test_expect_success 'pull in new branch to local repository' '
+	(cd localclone &&
+	git fetch origin default &&
+	test_must_fail git rev-parse -q --verify refs/remotes/origin/different-branch &&
+	git fetch &&
+	git rev-parse --no-revs --verify refs/remotes/origin/different-branch)
+'
+
+test_expect_success 'pull in new branch to remote repository' '
+	(cd clone &&
+	git fetch origin default &&
+	test_must_fail git rev-parse -q --verify refs/remotes/origin/different-branch &&
+	git fetch &&
+	git rev-parse --no-revs --verify refs/remotes/origin/different-branch)
+'
+
+test_done

From 30eff63b867bb722ef8c589eacdcaf4c8add1b4d Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Sat, 3 Mar 2012 19:53:38 +0100
Subject: [PATCH 3575/3720] t5800: clarify skip message

The skip message takes about remote-hg while the tests are about the
general remote helper framework (and don't require hg). Correct the
message.
---
 t/t5800-remote-helpers.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 4664696d00..2949b4548b 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -8,7 +8,7 @@ test_description='Test remote-helper import and export commands'
 . ./test-lib.sh
 
 if ! test_have_prereq PYTHON ; then
-	skip_all='skipping git-remote-hg tests, python not available'
+	skip_all='skipping remote helper tests, python not available'
 	test_done
 fi
 
@@ -17,7 +17,7 @@ import sys
 if sys.hexversion < 0x02040000:
     sys.exit(1)
 ' || {
-	skip_all='skipping git-remote-hg tests, python version < 2.4'
+	skip_all='skipping remote helper tests, python version < 2.4'
 	test_done
 }
 

From 39bc40f9191fecbc19d50c50e047e70a2b6629d7 Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Sat, 3 Mar 2012 19:57:22 +0100
Subject: [PATCH 3576/3720] t5801: skip without hg

The tests for remote-hg require hg, so skip them all when there is no
hg available.
---
 t/t5801-remote-hg.sh | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
index 18915ddb8c..2e68372d59 100755
--- a/t/t5801-remote-hg.sh
+++ b/t/t5801-remote-hg.sh
@@ -19,6 +19,12 @@ else
 	test_done
 fi
 
+if ! type hg >/dev/null 2>&1
+then
+	skip_all='skipping git remote-hg tests: requires hg'
+	test_done
+fi
+
 # Call cmp with the arguments -x ".hg" -x ".git"  
 
 vcs_cmp () {

From e91da96893cbed43056552be22100afb9bbebb71 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 29 Mar 2012 13:38:43 -0500
Subject: [PATCH 3577/3720] remote-hg: Postel's law dictates we should handle
 Author

We should handle a missing space before the email part of an author ident
gracefully. See for example the icedtea6 repository.

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index 758ba242d8..dd5756d4bb 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -76,7 +76,7 @@ class GitHg(object):
         author = ctx.user()
 
         # check for git author pattern compliance
-        regex = re.compile('^(.*?) \<(.*?)\>(.*)$')
+        regex = re.compile('^(.*?) ?\<(.*?)\>(.*)$')
         a = regex.match(author)
 
         if a:

From 06be0f29cbae2bc806faf9d555cd94d447cb97ef Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 00:27:45 -0500
Subject: [PATCH 3578/3720] remote-hg: another case of Postel's law

This change allows invalid input from Mercurial repositories where the
author is recorded as 'Name ').

With this change, importing http://scelenic.com/hg itself no longer fails
with:

	fatal: Missing > in ident string: Benoit Boissinot
	 1129685868 -0700

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index dd5756d4bb..cdd13fa513 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -76,17 +76,21 @@ class GitHg(object):
         author = ctx.user()
 
         # check for git author pattern compliance
-        regex = re.compile('^(.*?) ?\<(.*?)\>(.*)$')
+        regex = re.compile('^(.*?) ?\<(.*?)(|\>(.*))$')
         a = regex.match(author)
 
         if a:
             name = a.group(1)
             email = a.group(2)
-            if len(a.group(3)) > 0:
-                name += ' ext:(' + urllib.quote(a.group(3)) + ')'
+            extra = a.group(4)
+            if not extra is None and len(extra) > 0:
+                name += ' ext:(' + urllib.quote(extra) + ')'
             author = name + ' <' + email + '>'
         else:
-            author = author + ' '
+            if author.find('<') >= 0:
+                author = author + '>'
+            else:
+                author = author + ' '
 
         if 'author' in ctx.extra():
             author = apply_delta(author, ctx.extra()['author'])

From e362dae650c8cc132ab4ec419697d567c7fd27cc Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 00:56:31 -0500
Subject: [PATCH 3579/3720] remote-hg: handle another funny author line from
 http://scelenic.com/hg

In this case: David Soria Parra  php.net>.

With this last of three Postel patches, remote-hg can import the
Mercurial repository completely.

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index cdd13fa513..d835ed47e4 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -84,7 +84,13 @@ class GitHg(object):
             email = a.group(2)
             extra = a.group(4)
             if not extra is None and len(extra) > 0:
-                name += ' ext:(' + urllib.quote(extra) + ')'
+                if email.endswith('  ', '.')
+                    extra = extra.replace('>', '')
+                    email = email[:-4] + '@' + extra
+                else:
+                    name += ' ext:(' + urllib.quote(extra) + ')'
             author = name + ' <' + email + '>'
         else:
             if author.find('<') >= 0:

From e76a3d289b09d867c3cb8066bbd575f75809a719 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 01:01:21 -0500
Subject: [PATCH 3580/3720] Mark all remote-hg push tests as broken

For now, remote-hg cannot be used for pushing. The respective tests fail
thusly:

warning: non-alnum alias 'remote:///git/t/trash directory.t5801-remote-hg/empty'
transaction abort!
rollback completed
Traceback (most recent call last):
  File "/git/git-remote-hg", line 101, in 
    sys.exit(HgRemoteHelper().main(sys.argv))
  File ".../lib/git_remote_helpers/helper.py", line 197, in main
    more = self.read_one_line(repo)
  File ".../lib/git_remote_helpers/helper.py", line 163, in read_one_line
    func(repo, cmdline)
  File ".../lib/git_remote_helpers/helper.py", line 121, in do_export
    localrepo.importer.do_import(localrepo.gitdir)
  File ".../lib/git_remote_helpers/hg/importer.py", line 27, in do_import
    processor.parseMany(sources, parser.ImportParser, procc)
  File ".../lib/git_remote_helpers/fastimport/processor.py", line 219,
        in parseMany
    processor.process(parser.parse())
  File ".../lib/git_remote_helpers/fastimport/processor.py", line 76,
        in process
    handler(self, cmd)
  File ".../lib/git_remote_helpers/hg/hgimport.py", line 262,
        in commit_handler
    self.idmap[cmd.id] = self.putcommit(modified, modes, copies, cmt)
  File ".../lib/git_remote_helpers/hg/hgimport.py", line 294, in putcommit
    self.repo.commitctx(ctx)
  File "/lib/python/mercurial/localrepo.py", line 1315, in commitctx
    phases.retractboundary(self, targetphase, [n])
  File "/lib/python/mercurial/phases.py", line 201, in retractboundary
    currentroots.intersection_update(ctx.node() for ctx in ctxs)
  File "/lib/python/mercurial/phases.py", line 201, in 
    currentroots.intersection_update(ctx.node() for ctx in ctxs)
  File "/lib/python/mercurial/localrepo.py", line 264, in set
    for r in self.revs(expr, *args):
TypeError: 'set' object is not callable

Signed-off-by: Johannes Schindelin 
---
 t/t5801-remote-hg.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
index 2e68372d59..e0e60e8009 100755
--- a/t/t5801-remote-hg.sh
+++ b/t/t5801-remote-hg.sh
@@ -73,7 +73,7 @@ test_expect_success 'pulling from remote remote' '
 	vcs_cmp public clone
 '
 
-test_expect_success 'pushing to local empty repo' '
+test_expect_failure 'pushing to local empty repo' '
 	hg init localempty &&
 	(cd localclone &&
 	git push --all "hg::file://${ROOT}/localempty") &&
@@ -82,7 +82,7 @@ test_expect_success 'pushing to local empty repo' '
 	vcs_cmp localclone localempty
 '
 
-test_expect_success 'pushing to remote empty repo' '
+test_expect_failure 'pushing to remote empty repo' '
 	hg init empty &&
 	(cd localclone &&
 	git push --all "hg::remote://${ROOT}/empty") &&
@@ -91,7 +91,7 @@ test_expect_success 'pushing to remote empty repo' '
 	vcs_cmp localclone empty
 '
 
-test_expect_success 'pushing to local repo' '
+test_expect_failure 'pushing to local repo' '
 	(cd localclone &&
 	echo content >>file &&
 	git commit -a -m three &&
@@ -106,7 +106,7 @@ test_expect_success 'synch with changes from localclone' '
 	 git pull)
 '
 
-test_expect_success 'pushing remote local repo' '
+test_expect_failure 'pushing remote local repo' '
 	(cd clone &&
 	echo content >>file &&
 	git commit -a -m four &&

From f9d36ebf48a79da0d5fb18c2eb1eeca0cd4f6a80 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 02:12:53 -0500
Subject: [PATCH 3581/3720] remote-hg: do not interfer with hg's revs() method

Matt Mackall introduced a revs() method to the localrepo class on Wed
Nov 2 13:37:34 2011 in the commit 'localrepo: add revs helper method'.
It is used when constructing a commit in memory.

If we store the set of revs we want to handle under the same name, it
overrides that method, resulting in an unpleasant 'TypeError: 'set'
object is not callable' whenever we want to push (as we are constructing
commits in memory, then).

So let's work around that by renaming our field to 'revs2' and hope that
upstream Mercurial does not introduce a field of that name, too.

Signed-off-by: Johannes Schindelin 
---
 git-remote-hg.py               | 6 +++---
 git_remote_helpers/git/repo.py | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/git-remote-hg.py b/git-remote-hg.py
index fdf61a737d..1ee57f4009 100644
--- a/git-remote-hg.py
+++ b/git-remote-hg.py
@@ -42,7 +42,7 @@ class HgRemoteHelper(RemoteHelper):
         repo.marksfile = 'git.marks'
         repo.hg = hg
         repo.prefix = prefix
-        repo.revs = revs
+        repo.revs2 = revs # must not override repo.revs()
 
         self.setup_repo(repo, alias)
 
@@ -65,7 +65,7 @@ class HgRemoteHelper(RemoteHelper):
 
         local.git_hg = repo.git_hg
         local.hg = repo.hg
-        local.revs = repo.revs
+        local.revs2 = repo.revs2
         local.exporter = GitExporter(local)
         local.importer = GitImporter(local)
         local.is_local = repo.is_local
@@ -76,7 +76,7 @@ class HgRemoteHelper(RemoteHelper):
         """Lists all known references.
         """
 
-        for ref in repo.revs:
+        for ref in repo.revs2:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
index 4536233868..2bf6a729a4 100644
--- a/git_remote_helpers/git/repo.py
+++ b/git_remote_helpers/git/repo.py
@@ -61,7 +61,7 @@ class GitRepo(object):
         self.revmap = dict(sanitize(i) for i in output)
         if "HEAD" in self.revmap:
             del self.revmap["HEAD"]
-        self.revs = self.revmap.keys()
+        self.revs2 = self.revmap.keys()
         ofile.close()
 
     def get_head(self):

From 0e148f965ee523c9401c31d65eb8c1ab4293734e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 02:18:24 -0500
Subject: [PATCH 3582/3720] fixup! Mark all remote-hg push tests as broken

This reverts that. With the next rebasing merge, just 'git rebase
--continue'.
---
 t/t5801-remote-hg.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
index e0e60e8009..2e68372d59 100755
--- a/t/t5801-remote-hg.sh
+++ b/t/t5801-remote-hg.sh
@@ -73,7 +73,7 @@ test_expect_success 'pulling from remote remote' '
 	vcs_cmp public clone
 '
 
-test_expect_failure 'pushing to local empty repo' '
+test_expect_success 'pushing to local empty repo' '
 	hg init localempty &&
 	(cd localclone &&
 	git push --all "hg::file://${ROOT}/localempty") &&
@@ -82,7 +82,7 @@ test_expect_failure 'pushing to local empty repo' '
 	vcs_cmp localclone localempty
 '
 
-test_expect_failure 'pushing to remote empty repo' '
+test_expect_success 'pushing to remote empty repo' '
 	hg init empty &&
 	(cd localclone &&
 	git push --all "hg::remote://${ROOT}/empty") &&
@@ -91,7 +91,7 @@ test_expect_failure 'pushing to remote empty repo' '
 	vcs_cmp localclone empty
 '
 
-test_expect_failure 'pushing to local repo' '
+test_expect_success 'pushing to local repo' '
 	(cd localclone &&
 	echo content >>file &&
 	git commit -a -m three &&
@@ -106,7 +106,7 @@ test_expect_success 'synch with changes from localclone' '
 	 git pull)
 '
 
-test_expect_failure 'pushing remote local repo' '
+test_expect_success 'pushing remote local repo' '
 	(cd clone &&
 	echo content >>file &&
 	git commit -a -m four &&

From 6583d28f35fee84ef306dc72f4a0bbd9134c5761 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 22 Mar 2012 19:17:03 +0100
Subject: [PATCH 3583/3720] Windows: Always normalize paths to Windows-style

It appears that `pwd` returns the POSIX-style or the DOS-style path
depending which style the previous `cd` used. To normalize, enforce `pwd
-W` in scripts.

From the original e-mail exchange:

On Thu, Mar 22, 2012 at 11:13:37AM +0100, Sebastian Schuberth wrote:
> On Wed, Mar 21, 2012 at 22:21, Johannes Sixt  wrote:
>
> > I build git and run its tests outside the msysgit environment. Does that
> > explain the difference? (And I use CMD.)
>
> It does not make a difference for me. I started cmd.exe at
> c:\msysgit\git\t, added c:\msysgit\bin temporarily to PATH, and ran
> "sh t5526-fetch-submodules.sh -i -v", and the test still fails.

Yes it probably does. Johannes said that he runs the tests outside of
the msysgit folder. That way there is only one path the submodule script
gets reported and not two like '/c/msysgit/git' and '/git'.

That would explain to me why it is passing.

I am afraid that the only solution is to patch msys itself to report the
long absolute path when passing window style paths to cd. Currently when
I do

	cd c:/msysgit/git

I will end up in '/git' instead of the long path.

I found that there is a -W option to pwd in msys bash which makes it
always return the real windows path. A normalization in that direction
is unique and thus might be more robust. Have a look at the attached
patch. With this at least t5526 passes. I was not able to run the whole
testsuite properly at the moment. I can have a look at that tomorrow.

What do you think?

Cheers Heiko

Signed-off-by: Johannes Schindelin 
---
 git-sh-setup.sh  | 6 ++----
 git-submodule.sh | 3 ---
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index cc6fb913ce..b6c55e6dde 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -250,10 +250,8 @@ case $(uname -s) in
 	find () {
 		/usr/bin/find "$@"
 	}
-	# git sees Windows-style pwd
-	pwd () {
-		builtin pwd -W
-	}
+	# Let pwd always return the uniqe real windows path
+	alias pwd='pwd -W'
 	is_absolute_path () {
 		case "$1" in
 		[/\\]* | [A-Za-z]:*)
diff --git a/git-submodule.sh b/git-submodule.sh
index 289c2dd558..18515f6392 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -152,9 +152,6 @@ module_clone()
 
 	a=$(cd "$gitdir" && pwd)/
 	b=$(cd "$sm_path" && pwd)/
-	# normalize Windows-style absolute paths to POSIX-style absolute paths
-	case $a in [a-zA-Z]:/*) a=/${a%%:*}${a#*:} ;; esac
-	case $b in [a-zA-Z]:/*) b=/${b%%:*}${b#*:} ;; esac
 	# Remove all common leading directories after a sanity check
 	if test "${a#$b}" != "$a" || test "${b#$a}" != "$b"; then
 		die "$(eval_gettext "Gitdir '\$a' is part of the submodule path '\$b' or vice versa")"

From 507bb6d601f846701791713238331e9306ebe27e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 13:04:35 -0500
Subject: [PATCH 3584/3720] Always auto-gc after calling a fast-import
 transport

After importing anything with fast-import, we should always let the
garbage collector do its job, since the objects are written to disk
inefficiently.

This brings down an initial import of http://selenic.com/hg from about
230 megabytes to about 14.

In the future, we may want to make this configurable on a per-remote
basis, or maybe teach fast-import about it in the first place.

Signed-off-by: Johannes Schindelin 
---
 transport-helper.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index 3b6a9fa53d..5ff0e44a6d 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -12,6 +12,8 @@
 #include "sigchain.h"
 
 static int debug;
+/* TODO: put somewhere sensible, e.g. git_transport_options? */
+static int auto_gc = 1;
 
 struct helper_data {
 	const char *name;
@@ -476,6 +478,12 @@ static int fetch_with_import(struct transport *transport,
 		}
 	}
 	strbuf_release(&buf);
+	if (auto_gc) {
+		const char *argv_gc_auto[] = {
+			"gc", "--auto", "--quiet", NULL,
+		};
+		run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+	}
 	return 0;
 }
 

From f51b0fbc81b0f45888681341d90f6c5d781a118b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 14:47:14 -0500
Subject: [PATCH 3585/3720] fixup! remote-hg: do not interfer with hg's revs()
 method

---
 git-remote-testgit.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index d57c1dc393..f88a795951 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -56,7 +56,7 @@ class TestgitRemoteHelper(RemoteHelper):
         head is at clone time.
         """
 
-        for ref in repo.revs:
+        for ref in repo.revs2:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 

From 07bb9b302231f1b47cd5ef23c168070ad68c36cd Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 15:44:14 -0500
Subject: [PATCH 3586/3720] squash! remote-hg: do not interfer with hg's revs()
 method

FIXUP: the field is called 'revs_' now, Sverre likes that better.
---
 git-remote-hg.py               | 6 +++---
 git-remote-testgit.py          | 2 +-
 git_remote_helpers/git/repo.py | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/git-remote-hg.py b/git-remote-hg.py
index 1ee57f4009..4b619e9c4c 100644
--- a/git-remote-hg.py
+++ b/git-remote-hg.py
@@ -42,7 +42,7 @@ class HgRemoteHelper(RemoteHelper):
         repo.marksfile = 'git.marks'
         repo.hg = hg
         repo.prefix = prefix
-        repo.revs2 = revs # must not override repo.revs()
+        repo.revs_ = revs # must not override repo.revs()
 
         self.setup_repo(repo, alias)
 
@@ -65,7 +65,7 @@ class HgRemoteHelper(RemoteHelper):
 
         local.git_hg = repo.git_hg
         local.hg = repo.hg
-        local.revs2 = repo.revs2
+        local.revs_ = repo.revs_
         local.exporter = GitExporter(local)
         local.importer = GitImporter(local)
         local.is_local = repo.is_local
@@ -76,7 +76,7 @@ class HgRemoteHelper(RemoteHelper):
         """Lists all known references.
         """
 
-        for ref in repo.revs2:
+        for ref in repo.revs_:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 
diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index f88a795951..740e02b1f3 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -56,7 +56,7 @@ class TestgitRemoteHelper(RemoteHelper):
         head is at clone time.
         """
 
-        for ref in repo.revs2:
+        for ref in repo.revs_:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
index 2bf6a729a4..fa68e47101 100644
--- a/git_remote_helpers/git/repo.py
+++ b/git_remote_helpers/git/repo.py
@@ -61,7 +61,7 @@ class GitRepo(object):
         self.revmap = dict(sanitize(i) for i in output)
         if "HEAD" in self.revmap:
             del self.revmap["HEAD"]
-        self.revs2 = self.revmap.keys()
+        self.revs_ = self.revmap.keys()
         ofile.close()
 
     def get_head(self):

From fc57113a235a1ffda647f8da1850501f8f083842 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 16:37:57 -0500
Subject: [PATCH 3587/3720] fast-export: report SHA-1 instead of gibberish when
 marks exist already

Cc: Pieter de Bie 
Signed-off-by: Johannes Schindelin 
---
 builtin/fast-export.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 137792d49d..1213155acf 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -644,7 +644,7 @@ static void import_marks(char *input_file)
 			die ("Could not read blob %s", sha1_to_hex(sha1));
 
 		if (object->flags & SHOWN)
-			error("Object %s already has a mark", sha1);
+			error("Object %s already has a mark", sha1_to_hex(sha1));
 
 		mark_object(object, mark);
 		if (last_idnum < mark)

From 4504787b33dd975e1abfd896d1e4a7c4278597de Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 21:09:49 -0500
Subject: [PATCH 3588/3720] Windows: make sure that merge-octopus only outputs
 LF line endings

This happens to shut up t7602 on Windows which would otherwise take
the different line endings for a sign that the merge failed.

Signed-off-by: Johannes Schindelin 
---
 git-merge-octopus.sh | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh
index 8643f74cb0..2226eeba99 100755
--- a/git-merge-octopus.sh
+++ b/git-merge-octopus.sh
@@ -71,7 +71,9 @@ do
 
 	case "$LF$common$LF" in
 	*"$LF$SHA1$LF"*)
-		echo "Already up-to-date with $pretty_name"
+		cat << EOF
+Already up-to-date with $pretty_name
+EOF
 		continue
 		;;
 	esac
@@ -83,7 +85,9 @@ do
 		# tree as the intermediate result of the merge.
 		# We still need to count this as part of the parent set.
 
-		echo "Fast-forwarding to: $pretty_name"
+		cat << EOF
+Fast-forwarding to: $pretty_name
+EOF
 		git read-tree -u -m $head $SHA1 || exit
 		MRC=$SHA1 MRT=$(git write-tree)
 		continue
@@ -91,7 +95,9 @@ do
 
 	NON_FF_MERGE=1
 
-	echo "Trying simple merge with $pretty_name"
+	cat << EOF
+Trying simple merge with $pretty_name
+EOF
 	git read-tree -u -m --aggressive  $common $MRT $SHA1 || exit 2
 	next=$(git write-tree 2>/dev/null)
 	if test $? -ne 0

From 5f5ceee9b53721703edd8bbd414fdd328adb71ba Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 1 Mar 2012 21:53:54 +0100
Subject: [PATCH 3589/3720] Win32: fix broken pipe detection

As of "Win32: Thread-safe windows console output", git-log no longer
terminates when the pager process dies. This is due to disabling buffering
for the replaced stdout / stderr streams. Git-log will periodically fflush
stdout (see write_or_die.c/mayble_flush_or_die()), but with no buffering,
this is a NOP that always succeeds (so we never detect the EPIPE error).

Exchange the original console handles with our console thread pipe handles
by accessing the internal MSVCRT data structures directly (which are
exposed via __pioinfo for some reason).

Implement this with minimal assumptions about the actual data structure to
make it work with different (hopefully even future) MSVCRT versions.

While messing with internal data structures is ugly, this patch solves the
problem at the source instead of adding more workarounds. We no longer need
the special winansi_isatty override, and the limitations documented in
"Win32: Thread-safe windows console output" are gone (i.e. fdopen(1/2)
returns unbuffered streams now, and isatty() for duped console file
descriptors works as expected).

Signed-off-by: Karsten Blees 
---
 compat/mingw.h   |   2 -
 compat/winansi.c | 112 +++++++++++++++++++++++++++++------------------
 2 files changed, 69 insertions(+), 45 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 45f5569e53..8c46a5c76b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -306,9 +306,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  */
 
 void winansi_init(void);
-int winansi_isatty(int fd);
 HANDLE winansi_get_osfhandle(int fd);
-#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index 9f95954390..040ef5adca 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -7,11 +7,6 @@
 #include 
 #include 
 
-/*
- Functions to be wrapped:
-*/
-#undef isatty
-
 /*
  ANSI codes used by git: m, K
 
@@ -103,6 +98,7 @@ static int is_console(int fd)
 
 	/* initialize attributes */
 	if (!initialized) {
+		console = hcon;
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
@@ -463,29 +459,80 @@ static HANDLE duplicate_handle(HANDLE hnd)
 	return hresult;
 }
 
-static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+
+/*
+ * Make MSVCRT's internal file descriptor control structure accessible
+ * so that we can tweak OS handles and flags directly (we need MSVCRT
+ * to treat our pipe handle as if it were a console).
+ *
+ * We assume that the ioinfo structure (exposed by MSVCRT.dll via
+ * __pioinfo) starts with the OS handle and the flags. The exact size
+ * varies between MSVCRT versions, so we try different sizes until
+ * toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
+ * isatty(1).
+ */
+typedef struct {
+	HANDLE osfhnd;
+	char osflags;
+} ioinfo;
+
+extern __declspec(dllimport) ioinfo *__pioinfo[];
+
+static size_t sizeof_ioinfo = 0;
+
+#define IOINFO_L2E 5
+#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
+
+#define FDEV  0x40
+
+static inline ioinfo* _pioinfo(int fd)
 {
-	/* get original console handle */
-	int fd = _fileno(stream);
-	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
-	if (hcon == INVALID_HANDLE_VALUE)
-		die_errno("_get_osfhandle(%i) failed", fd);
+	return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
+			(fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
+}
 
-	/* save a copy to phcon and console (used by the background thread) */
-	console = *phcon = duplicate_handle(hcon);
+static int init_sizeof_ioinfo()
+{
+	int istty, wastty;
+	/* don't init twice */
+	if (sizeof_ioinfo)
+		return sizeof_ioinfo >= 256;
 
-	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
-	if (_dup2(new_fd, fd))
-		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+	sizeof_ioinfo = sizeof(ioinfo);
+	wastty = isatty(1);
+	while (sizeof_ioinfo < 256) {
+		/* toggle FDEV flag, check isatty, then toggle back */
+		_pioinfo(1)->osflags ^= FDEV;
+		istty = isatty(1);
+		_pioinfo(1)->osflags ^= FDEV;
+		/* return if we found the correct size */
+		if (istty != wastty)
+			return 0;
+		sizeof_ioinfo += sizeof(void*);
+	}
+	error("Tweaking file descriptors doesn't work with this MSVCRT.dll");
+	return 1;
+}
 
-	/* no buffering, or stdout / stderr will be out of sync */
-	setbuf(stream, NULL);
-	return (HANDLE) _get_osfhandle(fd);
+static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
+{
+	ioinfo *pioinfo;
+	HANDLE old_handle;
+
+	/* init ioinfo size if we haven't done so */
+	if (init_sizeof_ioinfo())
+		return INVALID_HANDLE_VALUE;
+
+	/* get ioinfo pointer and change the handles */
+	pioinfo = _pioinfo(fd);
+	old_handle = pioinfo->osfhnd;
+	pioinfo->osfhnd = new_handle;
+	return old_handle;
 }
 
 void winansi_init(void)
 {
-	int con1, con2, hwrite_fd;
+	int con1, con2;
 	char name[32];
 
 	/* check if either stdout or stderr is a console output screen buffer */
@@ -514,19 +561,11 @@ void winansi_init(void)
 	if (atexit(winansi_exit))
 		die_errno("atexit(winansi_exit) failed");
 
-	/* create a file descriptor for the write end of the pipe */
-	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
-	if (hwrite_fd == -1)
-		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
-
 	/* redirect stdout / stderr to the pipe */
 	if (con1)
-		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+		hconsole1 = swap_osfhnd(1, hwrite1 = duplicate_handle(hwrite));
 	if (con2)
-		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
-
-	/* close pipe file descriptor (also closes the duped hwrite) */
-	close(hwrite_fd);
+		hconsole2 = swap_osfhnd(2, hwrite2 = duplicate_handle(hwrite));
 }
 
 static int is_same_handle(HANDLE hnd, int fd)
@@ -534,19 +573,6 @@ static int is_same_handle(HANDLE hnd, int fd)
 	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
 }
 
-/*
- * Return true if stdout / stderr is a pipe redirecting to the console.
- */
-int winansi_isatty(int fd)
-{
-	if (fd == 1 && is_same_handle(hwrite1, 1))
-		return 1;
-	else if (fd == 2 && is_same_handle(hwrite2, 2))
-		return 1;
-	else
-		return isatty(fd);
-}
-
 /*
  * Returns the real console handle if stdout / stderr is a pipe redirecting
  * to the console. Allows spawn / exec to pass the console to the next process.

From 72f09446945d4c0dbd4842e3e9f4e5abe31e33a3 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 3 May 2012 12:34:12 -0500
Subject: [PATCH 3590/3720] fixup! submodule: Fix t7400, t7405, t7406 for
 msysGit

Between 132 patches to be rebased, an underscore got lost.
---
 git-submodule.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 18515f6392..f2dad1822f 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -266,7 +266,7 @@ cmd_add()
 	then
 		cat >&2 <
Date: Wed, 9 May 2012 12:35:02 -0300
Subject: [PATCH 3591/3720] fix build: compat/mingw.c:1236: error: conflicting
 types for 'mingw_execv' compat/../compat/mingw.h:294: note: previous
 declaration of 'mingw_execv' was here make: *** [compat/mingw.o] Error 1

---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 8c46a5c76b..4b80acafc8 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -291,7 +291,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 		     int fhin, int fhout, int fherr);
 int mingw_execvp(const char *cmd, char *const *argv);
 #define execvp mingw_execvp
-int mingw_execv(const char *cmd, char *const *argv);
+void mingw_execv(const char *cmd, char *const *argv);
 #define execv mingw_execv
 
 static inline unsigned int git_ntohl(unsigned int x)

From 7f0752666d34c32ab2c909b09514a621ca26ac9d Mon Sep 17 00:00:00 2001
From: Olivier Refalo 
Date: Wed, 9 May 2012 13:48:46 -0300
Subject: [PATCH 3592/3720] POSIX style 1/2

---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 4b80acafc8..8c46a5c76b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -291,7 +291,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 		     int fhin, int fhout, int fherr);
 int mingw_execvp(const char *cmd, char *const *argv);
 #define execvp mingw_execvp
-void mingw_execv(const char *cmd, char *const *argv);
+int mingw_execv(const char *cmd, char *const *argv);
 #define execv mingw_execv
 
 static inline unsigned int git_ntohl(unsigned int x)

From 2e8ce83fe823a367154ed65335ddebab44b593f5 Mon Sep 17 00:00:00 2001
From: Olivier Refalo 
Date: Wed, 9 May 2012 13:50:07 -0300
Subject: [PATCH 3593/3720] POSIX style 2/2

---
 compat/mingw.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 86c3fe7bdc..6025ac5eaf 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1233,7 +1233,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
 	return pid;
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
+int mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
 	if (!try_shell_exec(cmd, argv)) {
@@ -1241,11 +1241,12 @@ void mingw_execv(const char *cmd, char *const *argv)
 
 		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
-			return;
+			return -1;
 		if (waitpid(pid, &status, 0) < 0)
 			status = 255;
 		exit(status);
 	}
+	return -1;
 }
 
 int mingw_execvp(const char *cmd, char *const *argv)

From 7605b1c232340ab8d205fee7c77168fff8176e59 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 19 Apr 2012 18:21:29 -0500
Subject: [PATCH 3594/3720] Introduce and use test_cmp_text

On Windows, we suffer from frequently leaked DOS line endings. Let's
ignore them.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh          |  6 +-----
 t/t7407-submodule-foreach.sh | 26 +++-----------------------
 t/t9001-send-email.sh        | 31 +++++++++++++++----------------
 t/test-lib.sh                | 14 +++++++++++++-
 4 files changed, 32 insertions(+), 45 deletions(-)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 66dc4fd6c9..aac99ec6f5 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,11 +9,7 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
-	if test_have_prereq MINGW
-	then
-		dos2unix stderr
-	fi &&
-	test_cmp expect-stderr stderr
+	test_cmp_text expect-stderr stderr
 }
 
 read_chunk() {
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 03d2bd767d..a91102115b 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,10 +77,6 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -162,10 +158,6 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -184,11 +176,7 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 test_expect_success 'use "update --recursive" to checkout all submodules' '
@@ -235,11 +223,7 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 sed -e "/nested1 /s/.*/+$nested1sha1 nested1 (file2~1)/;/sub[1-3]/d" < expect > expect2
@@ -254,11 +238,7 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached
 		) &&
 		git submodule status --cached --recursive -- nested1 > ../actual
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 test_expect_success 'use "git clone --recursive" to checkout all submodules' '
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 8c12c65c72..8f7c9c4448 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -23,7 +23,6 @@ test_expect_success $PREREQ \
       echo do
       echo "  echo \"!\$a!\""
       echo "done >commandline\$output"
-      test_have_prereq MINGW && echo "dos2unix commandline\$output"
       echo "cat > msgtxt\$output"
       ) >fake.sendmail &&
      chmod +x ./fake.sendmail &&
@@ -97,7 +96,7 @@ EOF
 
 test_expect_success $PREREQ \
     'Verify commandline' \
-    'test_cmp expected commandline1'
+    'test_cmp_text expected commandline1'
 
 test_expect_success $PREREQ 'Send patches with --envelope-sender' '
     clean_fake_sendmail &&
@@ -117,7 +116,7 @@ EOF
 
 test_expect_success $PREREQ \
     'Verify commandline' \
-    'test_cmp expected commandline1'
+    'test_cmp_text expected commandline1'
 
 test_expect_success $PREREQ 'Send patches with --envelope-sender=auto' '
     clean_fake_sendmail &&
@@ -137,7 +136,7 @@ EOF
 
 test_expect_success $PREREQ \
     'Verify commandline' \
-    'test_cmp expected commandline1'
+    'test_cmp_text expected commandline1'
 
 test_expect_success $PREREQ 'setup expect' "
 cat >expected-show-all-headers <<\EOF
@@ -186,7 +185,7 @@ test_expect_success $PREREQ 'Show all headers' '
 		-e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
 		-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
 		>actual-show-all-headers &&
-	test_cmp expected-show-all-headers actual-show-all-headers
+	test_cmp_text expected-show-all-headers actual-show-all-headers
 '
 
 test_expect_success $PREREQ 'Prompting works' '
@@ -327,13 +326,13 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '
 		2>errors &&
 	# The first message is a reply to --in-reply-to
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual &&
-	test_cmp expect actual &&
+	test_cmp_text expect actual &&
 	# Second and subsequent messages are replies to the first one
 	sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual &&
-	test_cmp expect actual &&
+	test_cmp_text expect actual &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
@@ -348,13 +347,13 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
 		$patches $patches $patches \
 		2>errors &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual &&
-	test_cmp expect actual &&
+	test_cmp_text expect actual &&
 	sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual &&
-	test_cmp expect actual &&
+	test_cmp_text expect actual &&
 	sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt2 >expect &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 test_expect_success $PREREQ 'setup fake editor' '
@@ -426,7 +425,7 @@ test_suppression () {
 		-e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
 		-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
 		>actual-suppress-$1${2+"-$2"} &&
-	test_cmp expected-suppress-$1${2+"-$2"} actual-suppress-$1${2+"-$2"}
+	test_cmp_text expected-suppress-$1${2+"-$2"} actual-suppress-$1${2+"-$2"}
 }
 
 test_expect_success $PREREQ 'sendemail.cc set' '
@@ -1078,7 +1077,7 @@ test_expect_success $PREREQ 'asks about and fixes 8bit encodings' '
 	grep email-using-8bit stdout &&
 	grep "Which 8bit encoding" stdout &&
 	egrep "Content|MIME" msgtxt1 >actual &&
-	test_cmp actual content-type-decl
+	test_cmp_text actual content-type-decl
 '
 
 test_expect_success $PREREQ 'sendemail.8bitEncoding works' '
@@ -1089,7 +1088,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' '
 			--smtp-server="$(pwd)/fake.sendmail" \
 			email-using-8bit >stdout &&
 	egrep "Content|MIME" msgtxt1 >actual &&
-	test_cmp actual content-type-decl
+	test_cmp_text actual content-type-decl
 '
 
 test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
@@ -1101,7 +1100,7 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
 			--8bit-encoding=UTF-8 \
 			email-using-8bit >stdout &&
 	egrep "Content|MIME" msgtxt1 >actual &&
-	test_cmp actual content-type-decl
+	test_cmp_text actual content-type-decl
 '
 
 test_expect_success $PREREQ 'setup expect' '
@@ -1130,7 +1129,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
 			--8bit-encoding=UTF-8 \
 			email-using-8bit >stdout &&
 	grep "Subject" msgtxt1 >actual &&
-	test_cmp expected actual
+	test_cmp_text expected actual
 '
 
 # Note that the patches in this test are deliberately out of order; we
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 32a74a6e7a..8b6f59fecd 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -635,12 +635,24 @@ else
 	test_set_prereq C_LOCALE_OUTPUT
 fi
 
+# Use this instead of test_cmp to compare files that are expected to contain
+# text (and therefore it should not matter whether the line ends in an LF or
+# a CR/LF).
+test_cmp_text () {
+	if test_have_prereq MINGW
+	then
+		dos2unix "$1" &&
+		dos2unix "$2"
+	fi &&
+	test_cmp "$@"
+}
+
 # Use this instead of test_cmp to compare files that contain expected and
 # actual output from git commands that can be translated.  When running
 # under GETTEXT_POISON this pretends that the command produced expected
 # results.
 test_i18ncmp () {
-	test -n "$GETTEXT_POISON" || test_cmp "$@"
+	test -n "$GETTEXT_POISON" || test_cmp_text "$@"
 }
 
 # Use this instead of "grep expected-string actual" to see if the

From 741a88dbd570c01e17858d26c3fb5af99a852d65 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 12 Jan 2009 13:20:53 +0100
Subject: [PATCH 3595/3720] Make CFLAGS more strict

This is a gcc-ism, but as we use gcc exclusively, we can use them.

Taken from one of Junio's mails. (Reminded to cherry-pick this patch
by one of Karsten Blees' mails.)

Signed-off-by: Johannes Schindelin 
---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 96ebcf9830..cf82c4702d 100644
--- a/Makefile
+++ b/Makefile
@@ -316,7 +316,10 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -Werror \
+	-Wno-pointer-to-int-cast \
+	-Wold-style-definition \
+	-Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)

From 3d8a0d35fd88be9a7fd4c4dff6c365fc36b6a0ef Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 01:47:45 +0100
Subject: [PATCH 3596/3720] Do not compile compat/**/*.c with
 -Wold-style-definition

Signed-off-by: Johannes Schindelin 
---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index cf82c4702d..f9e058b457 100644
--- a/Makefile
+++ b/Makefile
@@ -2159,7 +2159,7 @@ endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
+C_OBJ := $(filter-out $(COMPAT_OBJS),$(filter-out $(ASM_OBJ),$(OBJECTS)))
 
 .SUFFIXES:
 
@@ -2199,6 +2199,8 @@ endif
 ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(COMPAT_OBJS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(filter-out -Wold-style-definition,$(ALL_CFLAGS)) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
 	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 endif

From 0b23940e84c0fba63e4b24022c528df3eed4b852 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 23 Nov 2011 10:41:01 +0100
Subject: [PATCH 3597/3720] Makefile: Do not use OLD_ICONV on MINGW anymore

We are building libiconv now the same way as upstream MinGW does, so we do
not need OLD_ICONV anymore when compiling Git either in msysGit or
mingwGitDevEnv.

Signed-off-by: Sebastian Schuberth 
---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index f9e058b457..cf535854b7 100644
--- a/Makefile
+++ b/Makefile
@@ -1312,7 +1312,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
-	OLD_ICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease

From 0d3f3db3498343df223f11947b1443261411b043 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 16:41:41 -0600
Subject: [PATCH 3598/3720] Define NO_GETTEXT for Git for Windows

The dreaded "your vnsprintf is broken (returned -1)" error is back. At
least with the libintl version we have. So for the moment, just work
around the issue by _not_ using gettext.

Ah, I wish that my attempt at implementing a custom strbuf_vaddf() would
not have been brushed aside so rashly. Oh well. Time saved on maintaining
that thing, I guess (although more time went into working around coping
with existing implementations).

Signed-off-by: Johannes Schindelin 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index cf535854b7..38fb812d54 100644
--- a/Makefile
+++ b/Makefile
@@ -1348,6 +1348,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 	NO_R_TO_GCC_LINKER = YesPlease
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
+	NO_GETTEXT = YesPlease
 else
 	NO_CURL = YesPlease
 endif

From 7508565998e729346ccee3e39ab3cff2fa27b65c Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Wed, 16 Dec 2009 22:20:55 +0100
Subject: [PATCH 3599/3720] core.hidedotfiles: hide '.git' dir by default

At least for cross-platform projects, it makes sense to hide the
files starting with a dot, as this is the behavior on Unix/MacOSX.

However, at least Eclipse has problems interpreting the hidden flag
correctly, so the default is to hide only the .git/ directory.

The config setting core.hideDotFiles therefore supports not only
'true' and 'false', but also 'dotGitOnly'.

[jes: clarified the commit message, made git init respect the setting
by marking the .git/ directory only after reading the config, and added
documentation, and rebased on top of current junio/next]

Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  6 ++++
 builtin/init-db.c        |  1 +
 cache.h                  |  7 +++++
 compat/mingw.c           | 65 ++++++++++++++++++++++++++++++++++++++--
 compat/mingw.h           |  8 ++---
 config.c                 |  9 ++++++
 environment.c            |  1 +
 git-compat-util.h        |  4 +++
 8 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 915cb5a547..9546f2f27b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -187,6 +187,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 will probe and set core.fileMode false if appropriate when the
 repository is created.
 
+core.hideDotFiles::
+	(Windows-only) If true (which is the default), mark newly-created
+	directories and files whose name starts with a dot as hidden.
+	If 'dotGitOnly', only the .git/ directory is hidden, but no other
+	files starting with a dot.
+
 core.ignoreCygwinFSTricks::
 	This option is only used by Cygwin implementation of Git. If false,
 	the Cygwin stat() and lstat() functions are used. This may be useful
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0dacb8b79c..4b1718f4b6 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -384,6 +384,7 @@ int init_db(const char *template_dir, unsigned int flags)
 	check_repository_format();
 
 	reinit = create_default_files(template_dir);
+	mark_as_git_dir(get_git_dir());
 
 	create_object_directory();
 
diff --git a/cache.h b/cache.h
index e14ffcd914..fefbe9a843 100644
--- a/cache.h
+++ b/cache.h
@@ -561,6 +561,13 @@ extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
 
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY,
+};
+extern enum hide_dotfiles_type hide_dotfiles;
+
 enum branch_track {
 	BRANCH_TRACK_UNSPECIFIED = -1,
 	BRANCH_TRACK_NEVER = 0,
diff --git a/compat/mingw.c b/compat/mingw.c
index afc892d6b1..671a539fbd 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -3,8 +3,10 @@
 #include 
 #include "../strbuf.h"
 #include "../run-command.h"
+#include "../cache.h"
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
+unsigned int _CRT_fmode = _O_BINARY;
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -278,6 +280,38 @@ int mingw_rmdir(const char *pathname)
 	return ret;
 }
 
+static int make_hidden(const char *path)
+{
+	DWORD attribs = GetFileAttributes(path);
+	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+void mingw_mark_as_git_dir(const char *dir)
+{
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+		warning("Failed to make '%s' hidden", dir);
+}
+
+#undef mkdir
+int mingw_mkdir(const char *path, int mode)
+{
+	int ret = mkdir(path);
+	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a directory is created.
+		 */
+		const char *start = basename((char*)path);
+		if (*start == '.')
+			return make_hidden(path);
+	}
+	return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -299,6 +333,17 @@ int mingw_open (const char *filename, int oflags, ...)
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
+	if ((oflags & O_CREAT) && fd >= 0 &&
+	    hide_dotfiles == HIDE_DOTFILES_TRUE) {
+		/*
+		 * In Windows a file or dir starting with a dot is not
+		 * automatically hidden. So lets mark it as hidden when
+		 * such a file is created.
+		 */
+		const char *start = basename((char*)filename);
+		if (*start == '.' && make_hidden(filename))
+			warning("Could not mark '%s' as hidden.", filename);
+	}
 	return fd;
 }
 
@@ -322,17 +367,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return fopen(filename, otype);
+	file = fopen(filename, otype);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 #undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
+	int hide = 0;
+	FILE *file;
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
+	    basename((char*)filename)[0] == '.')
+		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	return freopen(filename, otype, stream);
+	file = freopen(filename, otype, stream);
+	if (file && hide && make_hidden(filename))
+		warning("Could not mark '%s' as hidden.", filename);
+	return file;
 }
 
 /*
diff --git a/compat/mingw.h b/compat/mingw.h
index 61a652138a..75524124a9 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -114,10 +114,7 @@ static inline int fcntl(int fd, int cmd, ...)
  * simple adaptors
  */
 
-static inline int mingw_mkdir(const char *path, int mode)
-{
-	return mkdir(path);
-}
+int mingw_mkdir(const char *path, int mode);
 #define mkdir mingw_mkdir
 
 #define WNOHANG 1
@@ -319,6 +316,9 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
 
+void mingw_mark_as_git_dir(const char *dir);
+#define mark_as_git_dir mingw_mark_as_git_dir
+
 /*
  * helpers
  */
diff --git a/config.c b/config.c
index eeee986022..bb8b5698e7 100644
--- a/config.c
+++ b/config.c
@@ -758,6 +758,15 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly")) {
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+			return 0;
+		}
+		hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index d7e6c65763..d827d9e71d 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,7 @@ int core_apply_sparse_checkout;
 int merge_log_config = -1;
 struct startup_info *startup_info;
 unsigned long pack_size_limit_cfg;
+enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index ed11ad8119..14fa4e117a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -595,4 +595,8 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+#ifndef mark_as_git_dir
+#define mark_as_git_dir(x) /* noop */
+#endif
+
 #endif

From 19fc148f2a47aed12e7c0631b584f1c4ce2c457c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 9 Jan 2010 19:33:25 +0100
Subject: [PATCH 3600/3720] When initializing .git/, record the current setting
 of core.hideDotFiles

This is on Windows only, of course.

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 671a539fbd..5d8bddb3c5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -293,6 +293,10 @@ void mingw_mark_as_git_dir(const char *dir)
 {
 	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
+	git_config_set("core.hideDotFiles",
+		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
+		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
+		 "dotGitOnly" : "true"));
 }
 
 #undef mkdir

From 82e649e240d2032b9ac6e0cff4ec9f96f682e823 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Thu, 18 Mar 2010 10:21:31 +0000
Subject: [PATCH 3601/3720] mingw: do not hide bare repositories

As reported in msysGit issue 450 the recent change to set the windows
hidden attribute on the .git directory is being applied to bare git
directories. This patch excludes bare repositories.

Tested-by: Pat Thoyts 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 5d8bddb3c5..528a0d49f2 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -291,7 +291,8 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir))
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
+	    make_hidden(dir))
 		warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :

From 7471ab692a0721e991d7aaada8c800ec67389a87 Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Thu, 18 Mar 2010 11:48:50 +0000
Subject: [PATCH 3602/3720] mingw: add tests for the hidden attribute on the
 git directory

With msysGit the .git directory is supposed to be hidden, unless it is
a bare git repository. Test this.

Signed-off-by: Pat Thoyts 
---
 t/t0001-init.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index ad66410564..b157cb8581 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -417,4 +417,32 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
 	! test -d newdir/here
 '
 
+# Tests for the hidden file attribute on windows
+is_hidden () {
+	test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)"
+}
+
+test_expect_success MINGW 'plain hidden' '
+	rm -rf newdir &&
+	(
+		unset GIT_DIR GIT_WORK_TREE
+		mkdir newdir &&
+		cd newdir &&
+		git init &&
+		is_hidden .git
+	) &&
+	check_config newdir/.git false unset
+'
+
+test_expect_success MINGW 'plain bare not hidden' '
+	rm -rf newdir
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir newdir &&
+		cd newdir &&
+		git --bare init
+	) &&
+	! is_hidden newdir
+'
+
 test_done

From 3daeea173162215296cd9a12fcab9786b7c00e33 Mon Sep 17 00:00:00 2001
From: Matthieu Moy 
Date: Sat, 14 Jan 2012 19:55:36 +0100
Subject: [PATCH 3603/3720] bash-completion: don't add quoted space for ZSH
 (fix regression)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit a31e626 (completion: optimize refs completion) introduced a
regression for ZSH users: ref names were completed with a quoted trailing
space (i.e. "git checkout ma" completes to "git checkout master\ "). The
space is convenient for bash users since we use "-o nospace", but a
quoted space is worse than nothing. The absence of trailing space for ZSH
is a long-standing issue, that this patch is not fixing. We just fix the
regression by not appending a space when the shell is ZSH.

Original-patch-by: SZEDER Gábor 
Reported-by: Stefan Haller 
Signed-off-by: Matthieu Moy 
Signed-off-by: Junio C Hamano 
---
 contrib/completion/git-completion.bash | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 2f60825b21..d2693272c7 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -509,6 +509,13 @@ __gitcomp ()
 __gitcomp_nl ()
 {
 	local IFS=$'\n'
+
+	# ZSH would quote the trailing space added with -S. bash users
+	# will appreciate the extra space to compensate the use of -o nospace.
+	if [ -n "${ZSH_VERSION-}" ] && [ "$suffix" = " " ]; then
+		suffix=""
+	fi
+
 	COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
 }
 

From 667959384a332c4adc0c7afa1414b45413dfb4cc Mon Sep 17 00:00:00 2001
From: Johannes Sixt 
Date: Wed, 16 Sep 2009 16:06:53 +0200
Subject: [PATCH 3604/3720] criss cross rename failure workaround

Signed-off-by: Johannes Schindelin 
---
 t/t4130-apply-criss-cross-rename.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index d173acde0f..bf7049e7d9 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -14,8 +14,8 @@ create_file() {
 
 test_expect_success 'setup' '
 	create_file file1 "File1 contents" &&
-	create_file file2 "File2 contents" &&
-	create_file file3 "File3 contents" &&
+	create_file file2 "File2 more contents" &&
+	create_file file3 "File3 even more contents" &&
 	git add file1 file2 file3 &&
 	git commit -m 1
 '

From c4b316d30f347c24727c010bf60741d21c44e4e5 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 18 Feb 2010 18:27:27 +0100
Subject: [PATCH 3605/3720] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE
 after setup"

This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428.
---
 git-gui/git-gui.sh | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ba4e5c1330..498ee39919 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1316,9 +1316,6 @@ if {[lindex $_reponame end] eq {.git}} {
 	set _reponame [lindex $_reponame end]
 }
 
-set env(GIT_DIR) $_gitdir
-set env(GIT_WORK_TREE) $_gitworktree
-
 ######################################################################
 ##
 ## global init
@@ -2126,7 +2123,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs {is_submodule false}} {
 	global current_diff_path file_states current_diff_side ui_index
-	global _gitdir _gitworktree
+	global _gitworktree
 
 	# -- Always start gitk through whatever we were loaded with.  This
 	#    lets us bypass using shell process on Windows systems.
@@ -2138,12 +2135,19 @@ proc do_gitk {revs {is_submodule false}} {
 	} else {
 		global env
 
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
+
 		set pwd [pwd]
 
 		if {!$is_submodule} {
 			if {![is_bare]} {
 				cd $_gitworktree
 			}
+			set env(GIT_DIR) [file normalize [gitdir]]
 		} else {
 			cd $current_diff_path
 			if {$revs eq {--}} {
@@ -2164,18 +2168,15 @@ proc do_gitk {revs {is_submodule false}} {
 				}
 				set revs $old_sha1...$new_sha1
 			}
-			# GIT_DIR and GIT_WORK_TREE for the submodule are not the ones
-			# we've been using for the main repository, so unset them.
-			# TODO we could make life easier (start up faster?) for gitk
-			# by setting these to the appropriate values to allow gitk
-			# to skip the heuristics to find their proper value
-			unset env(GIT_DIR)
-			unset env(GIT_WORK_TREE)
+			if {[info exists env(GIT_DIR)]} {
+				unset env(GIT_DIR)
+			}
 		}
 		eval exec $cmd $revs "--" "--" &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg
@@ -2196,20 +2197,22 @@ proc do_git_gui {} {
 		error_popup [mc "Couldn't find git gui in PATH"]
 	} else {
 		global env
-		global _gitdir _gitworktree
 
-		# see note in do_gitk about unsetting these vars when
-		# running tools in a submodule
-		unset env(GIT_DIR)
-		unset env(GIT_WORK_TREE)
+		if {[info exists env(GIT_DIR)]} {
+			set old_GIT_DIR $env(GIT_DIR)
+			unset env(GIT_DIR)
+		} else {
+			set old_GIT_DIR {}
+		}
 
 		set pwd [pwd]
 		cd $current_diff_path
 
 		eval exec $exe gui &
 
-		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		if {$old_GIT_DIR ne {}} {
+			set env(GIT_DIR) $old_GIT_DIR
+		}
 		cd $pwd
 
 		ui_status $::starting_gitk_msg

From 38ad1c56953e120523f40c31b24126d72fac1ea9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 29 May 2010 21:50:11 +0200
Subject: [PATCH 3606/3720] git am: ignore dirty submodules

This fixes a rebase in the presence of dirty submodules. This is
orthogonal to the application of patches changing submodules.

Signed-off-by: Johannes Schindelin 
---
 git-am.sh | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index f8b7a0cb60..11ca959c3f 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -571,7 +571,8 @@ case "$resolved" in
 	'')
 		files=$(git ls-files) ;;
 	?*)
-		files=$(git diff-index --cached --name-only HEAD --) ;;
+		files=$(git diff-index --ignore-submodules --cached \
+			--name-only HEAD --) ;;
 	esac || exit
 	if test "$files"
 	then
@@ -743,7 +744,8 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		case "$resolved$interactive" in
 		tt)
 			# This is used only for interactive view option.
-			git diff-index -p --cached HEAD -- >"$dotest/patch"
+			git diff-index --ignore-submodules -p --cached \
+				HEAD -- >"$dotest/patch"
 			;;
 		esac
 	esac
@@ -819,7 +821,7 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
 		# trust what the user has in the index file and the
 		# working tree.
 		resolved=
-		git diff-index --quiet --cached HEAD -- && {
+		git diff-index --ignore-submodules --quiet --cached HEAD -- && {
 			gettextln "No changes - did you forget to use 'git add'?
 If there is nothing left to stage, chances are that something else
 already introduced the same changes; you might want to skip this patch."
@@ -843,7 +845,8 @@ did you forget to use 'git add'?"
 		then
 		    # Applying the patch to an earlier tree and merging the
 		    # result may have produced the same tree as ours.
-		    git diff-index --quiet --cached HEAD -- && {
+		    git diff-index --ignore-submodules --quiet --cached \
+				HEAD -- && {
 			say "$(gettext "No changes -- Patch already applied.")"
 			go_next
 			continue

From 96b803a0049762c1c1a2d841e0e3009219b8168a Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Sun, 21 Feb 2010 21:05:04 +0100
Subject: [PATCH 3607/3720] git-gui: provide question helper for retry fallback
 on Windows

Make use of the new environment variable GIT_ASK_YESNO to support the
recently implemented fallback in case unlink, rename or rmdir fail for
files in use on Windows. The added dialog will present a yes/no question
to the the user which will currently be used by the windows compat layer
to let the user retry a failed file operation.

Signed-off-by: Heiko Voigt 
---
 git-gui/Makefile          |  2 ++
 git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++
 git-gui/git-gui.sh        |  3 +++
 3 files changed, 56 insertions(+)
 create mode 100755 git-gui/git-gui--askyesno

diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c321..d50b455dce 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -290,6 +290,7 @@ install: all
 	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
 	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
@@ -308,6 +309,7 @@ uninstall:
 	$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1)
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1)
+	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1)
 	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true
 ifdef GITGUI_WINDOWS_WRAPPER
 	$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1)
diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno
new file mode 100755
index 0000000000..2a6e6fd111
--- /dev/null
+++ b/git-gui/git-gui--askyesno
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Tcl ignores the next line -*- tcl -*- \
+exec wish "$0" -- "$@"
+
+# This is an implementation of a simple yes no dialog
+# which is injected into the git commandline by git gui
+# in case a yesno question needs to be answered.
+
+set NS {}
+set use_ttk [package vsatisfies [package provide Tk] 8.5]
+if {$use_ttk} {
+	set NS ttk
+}
+
+if {$argc < 1} {
+	puts stderr "Usage: $argv0 "
+	exit 1
+} else {
+	set prompt [join $argv " "]
+}
+
+${NS}::frame .t
+${NS}::label .t.m -text $prompt -justify center -width 40
+.t.m configure -wraplength 400
+pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
+pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
+
+${NS}::frame .b
+${NS}::frame .b.left -width 200
+${NS}::button .b.yes -text Yes -command yes
+${NS}::button .b.no  -text No  -command no
+
+
+pack .b.left -side left -expand 1 -fill x
+pack .b.yes -side left -expand 1
+pack .b.no -side right -expand 1 -ipadx 5
+pack .b -side bottom -fill x -ipadx 20 -ipady 15
+
+bind .  {exit 0}
+bind .  {exit 1}
+
+proc no {} {
+	exit 1
+}
+
+proc yes {} {
+	exit 0
+}
+
+wm title . "Question?"
+tk::PlaceWindow .
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 498ee39919..20a38f5ce3 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASK_YESNO)]} {
+	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
+}
 
 ######################################################################
 ##

From 6b403cb1f5b3f127ec25010e827ad6b9e3332b2a Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 23 Jul 2010 18:06:05 +0200
Subject: [PATCH 3608/3720] git gui: set GIT_ASKPASS=git-gui--askpass if not
 set yet

Signed-off-by: Johannes Schindelin 
---
 git-gui/git-gui.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 20a38f5ce3..a59020bcc5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1224,6 +1224,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 if {![info exists env(SSH_ASKPASS)]} {
 	set env(SSH_ASKPASS) [gitexec git-gui--askpass]
 }
+if {![info exists env(GIT_ASKPASS)]} {
+	set env(GIT_ASKPASS) [gitexec git-gui--askpass]
+}
 if {![info exists env(GIT_ASK_YESNO)]} {
 	set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno]
 }

From c117035e2c4fbcbbdb3031c8122dbd878b4aa286 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:28:37 +0100
Subject: [PATCH 3609/3720] git-gui: fix encoding in git-gui file browser

Assume git tree objects (i.e. output of git-ls-tree) are encoded in system
encoding, for display in the git-gui file browser.

Signed-off-by: Karsten Blees 
---
 git-gui/lib/browser.tcl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 0328338fda..4fca8fb13c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary -encoding binary
+	fconfigure $fd -blocking 0 -translation binary
 	fileevent $fd readable [cb _read $fd]
 }
 

From 0b886c9f4d0ce0911f09f724103d684688f66890 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:38:07 +0100
Subject: [PATCH 3610/3720] gitk: fix file name encoding in diff hunk headers

Decode file names from system encoding in all diff hunk header lines, not
just the first (i.e. print nice file names in 'rename from' / 'rename to' /
'Binary files' lines, too).

Signed-off-by: Karsten Blees 
---
 gitk-git/gitk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 22270ce46b..0bfaa0f4ea 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7855,6 +7855,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
+	    set line [encoding convertfrom $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {

From 586978aa89ddb3a515a0c93830350facbf33e153 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 11 Aug 2009 02:22:33 +0200
Subject: [PATCH 3611/3720] Work around the command line limit on Windows

On Windows, there are dramatic problems when a command line grows
beyond PATH_MAX, which is restricted to 8191 characters on XP and
later (according to http://support.microsoft.com/kb/830473).

Work around this by just cutting off the command line at that length
(actually, at a space boundary) in the hope that only negative
refs are chucked: gitk will then do unnecessary work, but that is
still better than flashing the gitk window and exiting with exit
status 5 (which no Windows user is able to make sense of).

The first fix caused Tcl to fail to compile the regexp, see msysGit issue
427. Here is another fix without using regexp, and using a more relaxed
command line length limit to fix the original issue 387.

Signed-off-by: Sebastian Schuberth 
Signed-off-by: Pat Thoyts 
Signed-off-by: Johannes Schindelin 
---
 gitk-git/gitk | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 0bfaa0f4ea..bf2332cfc8 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9576,7 +9576,19 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set fd [open [concat $cmd $ids] r]
+	set cmd [concat $cmd $ids]
+	# The maximum command line length for the CreateProcess function is 32767 characters, see
+	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+	if {[tk windowingsystem] == "win32" &&
+		[string length $cmd] > 32000} {
+	    set ndx [string last " " $cmd 32000]
+	    if {$ndx != -1} {
+		set cmd [string range $cmd 0 $ndx]
+	    }
+	}
+	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
 	nowbusy allcommits

From e3c6171a9391ef01e1ec0e89fbbf9df06303cf96 Mon Sep 17 00:00:00 2001
From: "Chris West (Faux)" 
Date: Mon, 26 Jul 2010 00:36:19 +0100
Subject: [PATCH 3612/3720] Fix another invocation of git from gitk with an
 overly long command-line

Signed-off-by: Sebastian Schuberth 
---
 gitk-git/gitk | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index bf2332cfc8..16ff52a2c1 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -394,7 +394,7 @@ proc start_rev_list {view} {
 	if {$revs eq {}} {
 	    return 0
 	}
-	set args [concat $vflags($view) $revs]
+	set args [limit_arg_length [concat $vflags($view) $revs]]
     } else {
 	set args $vorigargs($view)
     }
@@ -9576,18 +9576,7 @@ proc getallcommits {} {
 	}
     }
     if {$ids ne {}} {
-	set cmd [concat $cmd $ids]
-	# The maximum command line length for the CreateProcess function is 32767 characters, see
-	# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
-	# Be a little conservative in case Tcl adds some more stuff to the command line we do not
-	# know about and truncate the command line at a SHA1-boundary below 32000 characters.
-	if {[tk windowingsystem] == "win32" &&
-		[string length $cmd] > 32000} {
-	    set ndx [string last " " $cmd 32000]
-	    if {$ndx != -1} {
-		set cmd [string range $cmd 0 $ndx]
-	    }
-	}
+	set cmd [limit_arg_length [concat $cmd $ids]]
 	set fd [open $cmd r]
 	fconfigure $fd -blocking 0
 	incr allcommits
@@ -9598,6 +9587,21 @@ proc getallcommits {} {
     }
 }
 
+# The maximum command line length for the CreateProcess function is 32767 characters, see
+# http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx
+# Be a little conservative in case Tcl adds some more stuff to the command line we do not
+# know about and truncate the command line at a SHA1-boundary below 32000 characters.
+proc limit_arg_length {cmd} {
+    if {[tk windowingsystem] == "win32" &&
+       [string length $cmd] > 32000} {
+        set ndx [string last " " $cmd 32000]
+        if {$ndx != -1} {
+            return [string range $cmd 0 $ndx]
+        }
+    }
+    return $cmd
+}
+
 # Since most commits have 1 parent and 1 child, we group strings of
 # such commits into "arcs" joining branch/merge points (BMPs), which
 # are commits that either don't have 1 parent or don't have 1 child.

From f9e1a5bd4bbebba375862319afb0f8e94509430d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 16 Feb 2009 21:52:51 +0100
Subject: [PATCH 3613/3720] Add a few more values for receive.denyCurrentBranch

For a long time, this developer thought that Git's insistence that
pushing into the current branch is evil was completely merited.

Just for fun, the original patch tried to show people that Git is right
there, and that it causes more trouble than it does good when Git allows
you to try to update the working tree for fast-forwards, or to detach the
HEAD, depending on some config settings.

Surprisingly, the opposite was shown.

So here is the support for two new options you can give the config
variable receive.denyCurrentBranch:

'updateInstead':
	Try to merge the working tree with the new tip of the branch
	(which can lead to really horrible merge conflicts).

'detachInstead':
	Detach the HEAD, thereby avoiding a disagreement between the
	HEAD and the index (as well as the working tree), possibly
	leaving the local user wondering how on earth her HEAD became
	so detached.

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  5 ++++
 builtin/receive-pack.c   | 58 ++++++++++++++++++++++++++++++++++++++--
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 9546f2f27b..0eb0a116b3 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1797,6 +1797,11 @@ receive.denyCurrentBranch::
 	print a warning of such a push to stderr, but allow the push to
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
++
+There are two more options that are meant for Git experts: "updateInstead"
+which will run `read-tree -u -m HEAD` and "detachInstead" which will detach
+the HEAD so it does not need to change.  Both options come with their own
+set of possible *complications*, but can be appropriate in rare workflows.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 0afb8b2896..1b2bf5fe66 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -19,7 +19,9 @@ enum deny_action {
 	DENY_UNCONFIGURED,
 	DENY_IGNORE,
 	DENY_WARN,
-	DENY_REFUSE
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD,
+	DENY_DETACH_INSTEAD,
 };
 
 static int deny_deletes;
@@ -89,7 +91,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 	}
 
 	if (!strcmp(var, "receive.denycurrentbranch")) {
-		deny_current_branch = parse_deny_action(var, value);
+		if (value && !strcasecmp(value, "updateinstead"))
+			deny_current_branch = DENY_UPDATE_INSTEAD;
+		else if (value && !strcasecmp(value, "detachinstead"))
+			deny_current_branch = DENY_DETACH_INSTEAD;
+		else
+			deny_current_branch = parse_deny_action(var, value);
 		return 0;
 	}
 
@@ -410,6 +417,44 @@ static void refuse_unconfigured_deny_delete_current(void)
 		rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
+static void merge_worktree(unsigned char *sha1)
+{
+	const char *update_refresh[] = {
+		"update-index", "--refresh", NULL
+	};
+	const char *read_tree[] = {
+		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
+	};
+	struct child_process child;
+	struct strbuf git_env = STRBUF_INIT;
+	const char *env[2];
+
+	if (is_bare_repository())
+		die ("denyCurrentBranch = updateInstead needs a worktree");
+
+	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+	env[0] = git_env.buf;
+	env[1] = NULL;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = update_refresh;
+	child.env = env;
+	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		die ("Could not refresh the index");
+
+	child.argv = read_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	if (run_command(&child))
+		die ("Could not merge working tree with new HEAD.  Good luck.");
+
+	strbuf_release(&git_env);
+}
+
 static const char *update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -441,6 +486,13 @@ static const char *update(struct command *cmd)
 			if (deny_current_branch == DENY_UNCONFIGURED)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
+		case DENY_UPDATE_INSTEAD:
+			merge_worktree(new_sha1);
+			break;
+		case DENY_DETACH_INSTEAD:
+			update_ref("push into current branch (detach)", "HEAD",
+				old_sha1, NULL, REF_NODEREF, DIE_ON_ERR);
+			break;
 		}
 	}
 
@@ -469,6 +521,8 @@ static const char *update(struct command *cmd)
 					refuse_unconfigured_deny_delete_current();
 				rp_error("refusing to delete the current branch: %s", name);
 				return "deletion of the current branch prohibited";
+			default:
+				die ("Invalid denyDeleteCurrent setting");
 			}
 		}
 	}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b5417cc951..2482796454 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -995,4 +995,40 @@ test_expect_success 'push --prune refspec' '
 	! check_push_result $the_first_commit tmp/foo tmp/bar
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+	git push testrepo master &&
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch updateInstead
+	) &&
+	test_commit third path2 &&
+	git push testrepo master &&
+	test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) &&
+	test third = "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
+test_expect_success 'receive.denyCurrentBranch = detachInstead' '
+	(cd testrepo &&
+		git reset --hard &&
+		git config receive.denyCurrentBranch detachInstead
+	) &&
+	OLDHEAD=$(cd testrepo && git rev-parse HEAD) &&
+	test_commit fourth path2 &&
+	test fourth = "$(cat path2)" &&
+	git push testrepo master &&
+	test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) &&
+	test fourth != "$(cat testrepo/path2)" &&
+	(cd testrepo &&
+		test_must_fail git symbolic-ref HEAD &&
+		git update-index --refresh &&
+		git diff-files --quiet &&
+		git diff-index --cached HEAD --
+	)
+'
+
 test_done

From 3a9932546b19970a11008ea8e3f3224e180425b0 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Oct 2010 08:06:23 -0700
Subject: [PATCH 3614/3720] Let deny.currentBranch=updateInstead ignore
 submodules

They are not affected by the update anyway.

Signed-off-by: Johannes Schindelin 
---
 builtin/receive-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 1b2bf5fe66..b648c14a86 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -420,7 +420,7 @@ static void refuse_unconfigured_deny_delete_current(void)
 static void merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
-		"update-index", "--refresh", NULL
+		"update-index", "--ignore-submodules", "--refresh", NULL
 	};
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL

From 245aa93c2bde685a4d5e9537b2e5146a9c6991ec Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Mon, 27 Jul 2009 21:05:40 +0200
Subject: [PATCH 3615/3720] send-email: accept absolute path even on Windows

Signed-off-by: Johannes Schindelin 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index ef30c557c7..c42fb2a7aa 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1058,7 +1058,7 @@ X-Mailer: git-send-email $gitversion
 
 	if ($dry_run) {
 		# We don't want to send the email.
-	} elsif ($smtp_server =~ m#^/#) {
+	} elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {

From 8d094d770dcd3e130f905efdde07ff6f50f180da Mon Sep 17 00:00:00 2001
From: bert Dvornik 
Date: Sun, 23 May 2010 03:00:47 -0400
Subject: [PATCH 3616/3720] send-email: handle Windows paths for display just
 like we do for processing

In git-send-email.perl, here are two checks to determine if
$smtp_server is an absolute path (so it'll be treated as a mailer) or
not (so it'll be treated as a hostname).  The one that handles actual
mail processing has been taught to recognize Windows pathnames by
commit 33b2e81f.

The other check is just to tell the user what happened, so it's far
less important, but the current state is that we will still claim to
the user that c:/foo/bar is a server. =)  This makes the second check
consistent with the first.

Signed-off-by: bert Dvornik 
---
 git-send-email.perl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index c42fb2a7aa..03292fd832 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1150,7 +1150,7 @@ X-Mailer: git-send-email $gitversion
 		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
 		print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
-		if ($smtp_server !~ m#^/#) {
+		if ($smtp_server !~ m#^/# && $smtp_server !~ m#[a-zA-Z]:#) {
 			print "Server: $smtp_server\n";
 			print "MAIL FROM:<$raw_from>\n";
 			foreach my $entry (@recipients) {

From b30dff683618dffdf348cce17f8bbf0175e635dc Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Wed, 2 Jun 2010 00:41:33 +0200
Subject: [PATCH 3617/3720] Add a Windows-specific fallback to getenv("HOME");

This fixes msysGit issue 482 properly.

Signed-off-by: Johannes Schindelin 
---
 builtin/config.c  |  4 ++--
 compat/mingw.c    | 18 ++++++++++++++++++
 compat/mingw.h    |  3 +++
 config.c          |  2 +-
 git-compat-util.h |  4 ++++
 path.c            |  2 +-
 6 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/builtin/config.c b/builtin/config.c
index 33c8820af6..e24586efa5 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -169,7 +169,7 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = given_config_file;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		local = repo_config = git_pathdup("config");
 		if (home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -379,7 +379,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		const char *home = get_home_directory();
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			given_config_file = user_config;
diff --git a/compat/mingw.c b/compat/mingw.c
index 528a0d49f2..38b5807f4b 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1831,3 +1831,21 @@ pid_t waitpid(pid_t pid, int *status, int options)
 	errno = EINVAL;
 	return -1;
 }
+
+const char *get_windows_home_directory(void)
+{
+	static const char *home_directory = NULL;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (home_directory)
+		return home_directory;
+
+	home_directory = getenv("HOME");
+	if (home_directory && *home_directory)
+		return home_directory;
+
+	strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+	home_directory = strbuf_detach(&buf, NULL);
+
+	return home_directory;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 75524124a9..2fcc935b78 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -350,3 +350,6 @@ static int mingw_main(c,v)
  * Used by Pthread API implementation for Windows
  */
 extern int err_win_to_posix(DWORD winerr);
+
+extern const char *get_windows_home_directory();
+#define get_home_directory() get_windows_home_directory()
diff --git a/config.c b/config.c
index bb8b5698e7..96661cd547 100644
--- a/config.c
+++ b/config.c
@@ -968,7 +968,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = get_home_directory();
 	if (home) {
 		char buf[PATH_MAX];
 		char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
diff --git a/git-compat-util.h b/git-compat-util.h
index 14fa4e117a..5911e8f7eb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -599,4 +599,8 @@ int remove_or_warn(unsigned int mode, const char *path);
 #define mark_as_git_dir(x) /* noop */
 #endif
 
+#ifndef get_home_directory
+#define get_home_directory() getenv("HOME")
+#endif
+
 #endif
diff --git a/path.c b/path.c
index 6f2aa699ad..4cb0585cde 100644
--- a/path.c
+++ b/path.c
@@ -240,7 +240,7 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = get_home_directory();
 			if (!home)
 				goto return_null;
 			strbuf_add(&user_path, home, strlen(home));

From ff1a6413e1bf4c873b9a2fd3e45895e1c0b9f218 Mon Sep 17 00:00:00 2001
From: Cezary Zawadka 
Date: Tue, 13 Jul 2010 16:17:43 +0200
Subject: [PATCH 3618/3720] Allow using UNC path for git repository

[efl: moved MinGW-specific part to compat/]

[jes: fixed compilation on non-Windows]

Signed-off-by: Cezary Zawadka 
Signed-off-by: Erik Faye-Lund 
Signed-off-by: Johannes Schindelin 
---
 cache.h           |  1 -
 compat/mingw.c    | 23 +++++++++++++++++++++++
 compat/mingw.h    |  2 ++
 git-compat-util.h |  4 ++++
 path.c            |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/cache.h b/cache.h
index fefbe9a843..30e9ac6190 100644
--- a/cache.h
+++ b/cache.h
@@ -729,7 +729,6 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/mingw.c b/compat/mingw.c
index 38b5807f4b..769ab0e267 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1849,3 +1849,26 @@ const char *get_windows_home_directory(void)
 
 	return home_directory;
 }
+
+int mingw_offset_1st_component(const char *path)
+{
+	if (has_dos_drive_prefix(path))
+		return 2 + is_dir_sep(path[2]);
+
+	/* unc paths */
+	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+
+		/* skip server name */
+		char *pos = strpbrk(path + 2, "\\/");
+		if (!pos)
+			return 0;
+
+		do {
+			pos++;
+		} while (*pos && !is_dir_sep(*pos));
+
+		return pos - path;
+	}
+
+	return is_dir_sep(path[0]);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 2fcc935b78..1e5ec25cdc 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -310,6 +310,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 	return ret;
 }
 #define find_last_dir_sep mingw_find_last_dir_sep
+int mingw_offset_1st_component(const char *path);
+#define offset_1st_component mingw_offset_1st_component
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 5911e8f7eb..39866a76c2 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,6 +211,10 @@ extern char *gitbasename(char *);
 #define has_dos_drive_prefix(path) 0
 #endif
 
+#ifndef offset_1st_component
+#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#endif
+
 #ifndef is_dir_sep
 #define is_dir_sep(c) ((c) == '/')
 #endif
diff --git a/path.c b/path.c
index 4cb0585cde..242074b1cf 100644
--- a/path.c
+++ b/path.c
@@ -660,10 +660,3 @@ int daemon_avoid_alias(const char *p)
 		}
 	}
 }
-
-int offset_1st_component(const char *path)
-{
-	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
-	return is_dir_sep(path[0]);
-}

From 7bb9cd3aee4f77ddea009b623018baad7c8a8e8f Mon Sep 17 00:00:00 2001
From: Eric Sunshine 
Date: Tue, 13 Jul 2010 12:19:52 -0400
Subject: [PATCH 3619/3720] Make mingw_offset_1st_component() behave
 consistently for all paths.

mingw_offset_1st_component() returns "foo" for inputs "/foo" and
"c:/foo", but inconsistently returns "/foo" for UNC input
"/machine/share/foo".  Fix it to return "foo" for all cases.

Reference: http://groups.google.com/group/msysgit/browse_thread/thread/c0af578549b5dda0

Signed-off-by: Eric Sunshine 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 769ab0e267..fce42fabe6 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1852,23 +1852,24 @@ const char *get_windows_home_directory(void)
 
 int mingw_offset_1st_component(const char *path)
 {
+	int offset = 0;
 	if (has_dos_drive_prefix(path))
-		return 2 + is_dir_sep(path[2]);
+		offset = 2;
 
 	/* unc paths */
-	if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
+	else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
 
 		/* skip server name */
 		char *pos = strpbrk(path + 2, "\\/");
 		if (!pos)
-			return 0;
+			return 0; /* Error: malformed unc path */
 
 		do {
 			pos++;
 		} while (*pos && !is_dir_sep(*pos));
 
-		return pos - path;
+		offset = pos - path;
 	}
 
-	return is_dir_sep(path[0]);
+	return offset + is_dir_sep(path[offset]);
 }

From 24364cf3a799b581a2c1b8fe36eb091d59b37fe8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 26 Jul 2009 05:08:42 +0200
Subject: [PATCH 3620/3720] Handle http.* config variables pointing to files
 gracefully on Windows

On Windows, we would like to be able to have a default http.sslCAinfo
that points to an MSys path (i.e. relative to the installation root of
Git).  As Git is a MinGW program, it has to handle the conversion
of the MSys path into a MinGW32 path itself.

Since system_path() considers paths starting with '/' as absolute, we
have to convince it to make a Windows path by stripping the leading
slash.

Signed-off-by: Johannes Schindelin 
---
 http.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c
index 5cb87f16f2..0270a3f883 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "url.h"
 #include "credential.h"
+#include "exec_cmd.h"
 
 int active_requests;
 int http_is_verbose;
@@ -138,6 +139,18 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int git_config_path(const char **result,
+		const char *var, const char *value)
+{
+	if (git_config_string(result, var, value))
+		return 1;
+#ifdef __MINGW32__
+	if (**result == '/')
+		*result = system_path((*result) + 1);
+#endif
+	return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
@@ -145,17 +158,17 @@ static int http_options(const char *var, const char *value, void *cb)
 		return 0;
 	}
 	if (!strcmp("http.sslcert", var))
-		return git_config_string(&ssl_cert, var, value);
+		return git_config_path(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (!strcmp("http.sslkey", var))
-		return git_config_string(&ssl_key, var, value);
+		return git_config_path(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var))
-		return git_config_string(&ssl_capath, var, value);
+		return git_config_path(&ssl_capath, var, value);
 #endif
 	if (!strcmp("http.sslcainfo", var))
-		return git_config_string(&ssl_cainfo, var, value);
+		return git_config_path(&ssl_cainfo, var, value);
 	if (!strcmp("http.sslcertpasswordprotected", var)) {
 		if (git_config_bool(var, value))
 			ssl_cert_password_required = 1;

From e93856342a8db118bedd4413b8caeba5bc2bea6a Mon Sep 17 00:00:00 2001
From: Evgeny Pashkin 
Date: Thu, 29 Sep 2011 22:32:37 +0400
Subject: [PATCH 3621/3720] Fixed wrong path delimiter in exe finding

On Windows XP3 in git bash
git clone git@github.com:octocat/Spoon-Knife.git
cd Spoon-Knife
git gui
menu Remote\Fetch from\origin
error: cannot spawn git: No such file or directory
error: could not run rev-list

if u run
git fetch --all
it worked normal in git bash or gitgui tools

In second version CreateProcess get 'C:\Git\libexec\git-core/git.exe' in
first version - C:/Git/libexec/git-core/git.exe and not executes (unix
slashes)

after fixing C:\Git\libexec\git-core\git.exe or
C:/Git/libexec/git-core\git.exe it works normal

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index fce42fabe6..a9e23c4842 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -817,7 +817,7 @@ static void free_path_split(char **path)
 static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 {
 	char path[MAX_PATH];
-	snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+	snprintf(path, sizeof(path), "%s\\%s.exe", dir, cmd);
 
 	if (!isexe && access(path, F_OK) == 0)
 		return xstrdup(path);

From 814bb0b10197c368f0e21e120cc7ca104c4f65f9 Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Thu, 22 Mar 2012 19:17:03 +0100
Subject: [PATCH 3622/3720] Windows: Always normalize paths to Windows-style

It appears that `pwd` returns the POSIX-style or the DOS-style path
depending which style the previous `cd` used. To normalize, enforce `pwd
-W` in scripts.

From the original e-mail exchange:

On Thu, Mar 22, 2012 at 11:13:37AM +0100, Sebastian Schuberth wrote:
> On Wed, Mar 21, 2012 at 22:21, Johannes Sixt  wrote:
>
> > I build git and run its tests outside the msysgit environment. Does that
> > explain the difference? (And I use CMD.)
>
> It does not make a difference for me. I started cmd.exe at
> c:\msysgit\git\t, added c:\msysgit\bin temporarily to PATH, and ran
> "sh t5526-fetch-submodules.sh -i -v", and the test still fails.

Yes it probably does. Johannes said that he runs the tests outside of
the msysgit folder. That way there is only one path the submodule script
gets reported and not two like '/c/msysgit/git' and '/git'.

That would explain to me why it is passing.

I am afraid that the only solution is to patch msys itself to report the
long absolute path when passing window style paths to cd. Currently when
I do

	cd c:/msysgit/git

I will end up in '/git' instead of the long path.

I found that there is a -W option to pwd in msys bash which makes it
always return the real windows path. A normalization in that direction
is unique and thus might be more robust. Have a look at the attached
patch. With this at least t5526 passes. I was not able to run the whole
testsuite properly at the moment. I can have a look at that tomorrow.

What do you think?

Cheers Heiko

Signed-off-by: Johannes Schindelin 
---
 git-sh-setup.sh  | 6 ++----
 git-submodule.sh | 3 ---
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 7b3ae75d7a..db0849cc98 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -248,10 +248,8 @@ case $(uname -s) in
 	find () {
 		/usr/bin/find "$@"
 	}
-	# git sees Windows-style pwd
-	pwd () {
-		builtin pwd -W
-	}
+	# Let pwd always return the uniqe real windows path
+	alias pwd='pwd -W'
 	is_absolute_path () {
 		case "$1" in
 		[/\\]* | [A-Za-z]:*)
diff --git a/git-submodule.sh b/git-submodule.sh
index 64a70d621a..a7007a77ae 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -152,9 +152,6 @@ module_clone()
 
 	a=$(cd "$gitdir" && pwd)/
 	b=$(cd "$sm_path" && pwd)/
-	# normalize Windows-style absolute paths to POSIX-style absolute paths
-	case $a in [a-zA-Z]:/*) a=/${a%%:*}${a#*:} ;; esac
-	case $b in [a-zA-Z]:/*) b=/${b%%:*}${b#*:} ;; esac
 	# Remove all common leading directories after a sanity check
 	if test "${a#$b}" != "$a" || test "${b#$a}" != "$b"; then
 		die "$(eval_gettext "Gitdir '\$a' is part of the submodule path '\$b' or vice versa")"

From f8b177a84f6892ee333492a7cb51d704d7beca98 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 14:43:00 +0200
Subject: [PATCH 3623/3720] gitweb: Allow line number toggling with Javascript

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 55e0e9ea38..f9d730a93c 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4458,6 +4458,25 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
+			print '    
+
+
+';
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 0fc8c548678d808ab0b9fcc238ca6f492189f727 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 7 Sep 2010 16:58:16 +0200
Subject: [PATCH 3624/3720] Gitweb: make line number toggling work for Firefox
 and Safari

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f9d730a93c..fc8cabff91 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4473,7 +4473,9 @@ function toggleLineNumbers() {
                 e2.innerHTML = "[Hide line numbers]";
         }
 }
-document.getElementsByTagName("head")[0].innerHTML += "";
+var style = document.createElement("style");
+style.setAttribute("id", "lineNoStyle");
+document.getElementsByTagName("head")[0].appendChild(style);
 toggleLineNumbers();
 
 ';

From 6364d78dd8423912e51edafc238d6003584995ac Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 03:02:57 -0500
Subject: [PATCH 3625/3720] Gitweb: add support for Alex Gorbatchev's
 SyntaxHighlighter in Javascript

Gitweb is not exactly what you would call server-friendly, so let's
offload one more task onto the client.

To enable this, put something like this into your gitweb_config.perl:

	$feature{'syntaxhighlighter_js'}{'default'} = [{
		url => '/SyntaxHighlighter/',
		style => 'Django',
		theme => 'FadeToGrey'
	}];

and clone git://github.com/alexgorbatchev/SyntaxHighlighter into the
directory you specified via the 'url' parameter.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index fc8cabff91..8fdda5b711 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -6979,7 +6979,19 @@ sub git_blob {
 	# we can have blame only for text/* mimetype
 	$have_blame &&= ($mimetype =~ m!^text/!);
 
+	my $highlight_js = gitweb_check_feature('syntaxhighlighter_js');
+	if ($highlight_js) {
+		push @stylesheets, $highlight_js->{url} . '/styles/shCore'
+			. $highlight_js->{style} . '.css';
+		push @stylesheets, $highlight_js->{url} . '/styles/shTheme'
+			. $highlight_js->{theme} . '.css';
+	}
+
 	my $highlight = gitweb_check_feature('highlight');
+	if ($highlight_js && $highlight) {
+		die_error(500, 'The highlight and syntaxhighlighter_js are'
+			. 'mutually exclusive');
+	}
 	my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
 	$fd = run_highlighter($fd, $highlight, $syntax)
 		if $syntax;
@@ -7027,6 +7039,58 @@ sub git_blob {
 		      href(action=>"blob_plain", hash=>$hash,
 		           hash_base=>$hash_base, file_name=>$file_name) .
 		      qq!" />\n!;
+	} elsif ($highlight_js) {
+		my $ext = $file_name;
+		$ext =~ s/.*\.//;
+		print qq!
!;
+		while (my $line = <$fd>) {
+			$line =~ s!&!\&!g;
+			$line =~ s!!;
+		foreach my $name ('Core', 'Autoloader') {
+			print qq!!;
+		}
+		print qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From 030544c914696c7c8affa58c35f582a5e849d75d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sun, 25 Sep 2011 10:23:29 +0200
Subject: [PATCH 3626/3720] Only switch on the line number toggle when
 highlighting is activated

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 8fdda5b711..2e485a0a66 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4458,7 +4458,8 @@ sub git_print_page_path {
 			print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
 			                             hash_base=>$hb),
 			              -title => $name}, esc_path($basename));
-			print '    
+			if (gitweb_check_feature('highlight')) {
+				print '    
 
 
 ';
+			}
 		} elsif (defined $type && $type eq 'tree') {
 			print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
 			                             hash_base=>$hb),

From 58a99ac988596a75766abae1d05eafaa21651525 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 26 Sep 2011 20:53:09 +0200
Subject: [PATCH 3627/3720] gitweb (SyntaxHighlighter): interpret
 #l

It is pretty convenient to refer to a line number by appending, say,
highlighter, too.

Signed-off-by: Johannes Schindelin 
---
 gitweb/gitweb.perl | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 2e485a0a66..1f48f1d4b5 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -7092,7 +7092,21 @@ sub git_blob {
 			$lang =~ s! (\S+)$! $brush_prefix$1!;
 			print "'".$lang.qq!.js',!;
 		}
-		print qq!''); SyntaxHighlighter.all();!;
+		print qq!''); SyntaxHighlighter.all();!
+			.qq!function scrollTo(number) {!
+			.qq!  var elements = document.getElementsByClassName(number);!
+			.qq!  if (elements.length == 0) setTimeout('scrollTo("' + number + '");', 50);!
+			.qq!  else {!
+			.qq!    window.scroll(0, elements[0].offsetTop);!
+			.qq!    window.scrollTo(0, elements[0].offsetTop);!
+			.qq!    elements[0].style.color = '#ff0000';!
+			.qq!  }!
+			.qq!}!
+			.qq!var lineRegex = /#l(\\d+)\$/;!
+			.qq!var lineNumber = lineRegex.exec(document.URL);!
+			.qq!if (lineNumber)!
+			.qq!  scrollTo('number' + lineNumber[1]);!
+			.qq!!;
 	} else {
 		my $nr;
 		while (my $line = <$fd>) {

From ba487c753bfd6d891feb325f847f7d3794baa37c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 8 Feb 2011 00:17:24 -0600
Subject: [PATCH 3628/3720] git grep -O -i: if the pager is 'less', pass the
 '-i' option

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 643938d905..01772271e9 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -949,6 +949,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		if (len > 4 && is_dir_sep(pager[len - 5]))
 			pager += len - 4;
 
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-i");
+
 		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "+/%s%s",

From 9fed48b1521a7928682c359bd047f8260bf80a85 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 8 Nov 2010 16:10:43 +0100
Subject: [PATCH 3629/3720] grep -I: do not bother to read known-binary files

Incidentally, this makes grep -I respect the "binary" attribute (actually,
the "-text" attribute, but "binary" implies that).

Since the attributes are not thread-safe, we now need to switch off
threading if -I was passed.

Signed-off-by: Johannes Schindelin 
---
 builtin/grep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/grep.c b/builtin/grep.c
index 01772271e9..3af417e76c 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
+#include "attr.h"
 
 static char const * const grep_usage[] = {
 	"git grep [options] [-e]  [...] [[--] ...]",
@@ -162,6 +163,22 @@ static void work_done(struct work_item *w)
 	grep_unlock();
 }
 
+static int skip_binary(struct grep_opt *opt, const char *filename)
+{
+	if ((opt->binary & GREP_BINARY_NOMATCH)) {
+		static struct git_attr *attr_text;
+		struct git_attr_check check;
+
+		if (!attr_text)
+			attr_text = git_attr("text");
+		memset(&check, 0, sizeof(check));
+		check.attr = attr_text;
+		return !git_check_attr(filename, 1, &check) &&
+				ATTR_FALSE(check.value);
+	}
+	return 0;
+}
+
 static void *run(void *arg)
 {
 	int hit = 0;
@@ -172,6 +189,9 @@ static void *run(void *arg)
 		if (!w)
 			break;
 
+		if (skip_binary(opt, (const char *)w->source.identifier))
+			continue;
+
 		opt->output_priv = w;
 		hit |= grep_source(opt, &w->source);
 		grep_source_clear_data(&w->source);
@@ -418,6 +438,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 			continue;
 		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 			continue;
+		if (skip_binary(opt, ce->name))
+			continue;
+
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
 		 * are identical, even if worktree file has been modified, so use
@@ -883,6 +906,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		string_list_append(&path_list, show_in_pager);
 		use_threads = 0;
 	}
+	if ((opt.binary & GREP_BINARY_NOMATCH))
+		use_threads = 0;
 
 	if (!opt.pattern_list)
 		die(_("no pattern given."));

From d6b32880be65e413da77b9db9b034e163466337e Mon Sep 17 00:00:00 2001
From: Gregor Uhlenheuer 
Date: Fri, 18 Feb 2011 11:42:12 +0100
Subject: [PATCH 3630/3720] Git.pm: Use stream-like writing in cat_blob()

This commit fixes the issue with the handling of large files causing an
'Out of memory' perl exception. Instead of reading and writing the whole
blob at once now the blob is written in small pieces.

The problem was raised and discussed in this mail to the msysGit mailing
list: http://thread.gmane.org/gmane.comp.version-control.msysgit/12080

Signed-off-by: Gregor Uhlenheuer 
Signed-off-by: Johannes Schindelin 
---
 perl/Git.pm | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/perl/Git.pm b/perl/Git.pm
index 497f420178..266c1236ff 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -888,22 +888,26 @@ sub cat_blob {
 	}
 
 	my $size = $1;
-
-	my $blob;
 	my $bytesRead = 0;
 
 	while (1) {
+		my $blob;
 		my $bytesLeft = $size - $bytesRead;
 		last unless $bytesLeft;
 
 		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
-		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		my $read = read($in, $blob, $bytesToRead);
 		unless (defined($read)) {
 			$self->_close_cat_blob();
 			throw Error::Simple("in pipe went bad");
 		}
 
 		$bytesRead += $read;
+
+		unless (print $fh $blob) {
+			$self->_close_cat_blob();
+			throw Error::Simple("couldn't write to passed in filehandle");
+		}
 	}
 
 	# Skip past the trailing newline.
@@ -918,11 +922,6 @@ sub cat_blob {
 		throw Error::Simple("didn't find newline after blob");
 	}
 
-	unless (print $fh $blob) {
-		$self->_close_cat_blob();
-		throw Error::Simple("couldn't write to passed in filehandle");
-	}
-
 	return $size;
 }
 

From af8a8d1b8bcd8a63766fe7d3b44a425efd23b258 Mon Sep 17 00:00:00 2001
From: Sebastian Schuberth 
Date: Wed, 27 Apr 2011 18:38:04 +0200
Subject: [PATCH 3631/3720] submodule: Use cat instead of echo to avoid DOS
 line-endings

In msysGit, echo used in scripts outputs DOS line-endings while built-ins
use Unix line-endings in their output. This causes t7508-status to fail
due to mixed line endings in the output of git status (which calls
git-submodule).

Signed-off-by: Sebastian Schuberth 
---
 git-submodule.sh | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index a7007a77ae..e92a674b42 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -833,12 +833,16 @@ cmd_summary() {
 	done |
 	if test -n "$for_status"; then
 		if [ -n "$files" ]; then
-			gettextln "# Submodules changed but not updated:"
+			status_msg="$(gettextln "# Submodules changed but not updated:")"
 		else
-			gettextln "# Submodule changes to be committed:"
+			status_msg="$(gettextln "# Submodule changes to be committed:")"
 		fi
-		echo "#"
-		sed -e 's|^|# |' -e 's|^# $|#|'
+		status_sed=$(sed -e 's|^|# |' -e 's|^# $|#|')
+		cat <
Date: Thu, 28 Apr 2011 00:30:49 +0200
Subject: [PATCH 3632/3720] submodule: Fix t7400, t7405, t7406 for msysGit

Again, avoid using echo (which issues DOS line endings on msysGit) to not mix
with Unix line-endings issued by git built-ins, even if this is at the cost of
calling an external executable (cat) instead of a shell built-in (echo).
---
 git-sh-setup.sh  | 4 +++-
 git-submodule.sh | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index db0849cc98..b6c55e6dde 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -55,7 +55,9 @@ GIT_QUIET=
 say () {
 	if test -z "$GIT_QUIET"
 	then
-		printf '%s\n' "$*"
+		cat < /dev/null 2>&1
 	then
-		eval_gettextln "The following path is ignored by one of your .gitignore files:
-\$sm_path
-Use -f if you really want to add it." >&2
+		cat >&2 <
Date: Fri, 23 Mar 2012 10:58:37 +0100
Subject: [PATCH 3633/3720] am: Use cat instead of echo to avoid DOS
 line-endings (fixes t4150)

Along the lines of 05d0e3b and f33946d, use cat instead of echo to avoid
line ending mismatches in the test result of "am empty-file does not
infloop" which make the test fail.

Signed-off-by: Sebastian Schuberth 
---
 git-am.sh | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/git-am.sh b/git-am.sh
index 11ca959c3f..c2f787c1f7 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -183,7 +183,9 @@ It does not apply to blobs recorded in its index.")"
 }
 
 clean_abort () {
-	test $# = 0 || echo >&2 "$@"
+	test $# = 0 || cat >&2 <
Date: Fri, 21 Oct 2011 23:27:09 -0500
Subject: [PATCH 3634/3720] Teach 'git pull' to handle --rebase=interactive

Signed-off-by: Johannes Schindelin 
---
 Documentation/git-pull.txt | 5 ++++-
 git-pull.sh                | 8 +++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index defb544ed0..7e4d30ef73 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -101,13 +101,16 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
---rebase::
+--rebase[=interactive]::
 	Rebase the current branch on top of the upstream branch after
 	fetching.  If there is a remote-tracking branch corresponding to
 	the upstream branch and the upstream branch was rebased since last
 	fetched, the rebase uses that information to avoid rebasing
 	non-local changes.
 +
+The optional mode `interactive` tells Git to switch on rebase's interactive
+mode.
++
 See `pull.rebase`, `branch..rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `--rebase` instead of merging.
diff --git a/git-pull.sh b/git-pull.sh
index 2a10047eb7..be1b098be0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ log_arg= verbosity= progress= recurse_submodules=
 merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
+rebase_options=
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
@@ -113,7 +114,12 @@ do
 	-r|--r|--re|--reb|--reba|--rebas|--rebase)
 		rebase=true
 		;;
+	--rebase=i|--rebase=interactive)
+		rebase_options=-i
+		rebase=true
+		;;
 	--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+		rebase_options=
 		rebase=false
 		;;
 	--recurse-submodules)
@@ -278,7 +284,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-	eval="git-rebase $diffstat $strategy_args $merge_args"
+	eval="git-rebase $rebase_options $diffstat $strategy_args $merge_args"
 	eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 	;;
 *)

From 4f2a4241d8c64c71fa1c99ccc455789820e0f50c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 21 Oct 2011 23:27:37 -0500
Subject: [PATCH 3635/3720] Handle the branch..rebase value 'interactive'

Signed-off-by: Johannes Schindelin 
---
 Documentation/config.txt |  1 +
 git-pull.sh              | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0eb0a116b3..2aba2a88fb 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -717,6 +717,7 @@ branch..rebase::
 	instead of merging the default branch from the default remote when
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
+	When the value is `interactive`, the rebase is run in interactive mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/git-pull.sh b/git-pull.sh
index be1b098be0..34b47c4fb2 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -44,7 +44,15 @@ merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase_options=
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+case "$(git config branch.$curr_branch_short.rebase)" in
+interactive)
+	rebase_options=-i
+	rebase=true
+	;;
+*)
+	rebase=$(git config --bool branch.$curr_branch_short.rebase)
+	;;
+esac
 if test -z "$rebase"
 then
 	rebase=$(git config --bool pull.rebase)

From 52e26344a134a3af72473e8973fd8096c72464c5 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 3 Feb 2012 00:12:04 -0600
Subject: [PATCH 3636/3720] Teach 'git remote' that the config var
 branch.*.rebase can be 'interactive'

Signed-off-by: Johannes Schindelin 
---
 builtin/remote.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index 0f0c594b2f..4b41e8c022 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -253,7 +253,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	int rebase;
+	enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
 };
 
 static struct string_list branch_list;
@@ -310,7 +310,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			}
 			string_list_append(&info->merge, xstrdup(value));
 		} else
-			info->rebase = git_config_bool(orig_key, value);
+			info->rebase = value && *value == 'i' ?
+				INTERACTIVE_REBASE :
+				(git_config_bool(orig_key, value) ?
+				 NORMAL_REBASE : NO_REBASE);
 	}
 	return 0;
 }
@@ -995,7 +998,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 
 	printf("    %-*s ", show_info->width, item->string);
 	if (branch_info->rebase) {
-		printf_ln(_("rebases onto remote %s"), merge->items[0].string);
+		printf_ln(_(branch_info->rebase == INTERACTIVE_REBASE ?
+			"rebases interactively onto remote %s" :
+			"rebases onto remote %s"), merge->items[0].string);
 		return 0;
 	} else if (show_info->any_rebase) {
 		printf_ln(_(" merges with remote %s"), merge->items[0].string);

From c0c56c0fe145e53257e7d124b5f7094340c1d716 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 8 Apr 2010 00:18:07 +0200
Subject: [PATCH 3637/3720] Work around funny CR issue

This is really a problem with shell scripts being called on msysGit,
but there are more important bugs to fix for the moment.

Signed-off-by: Johannes Schindelin 
---
 t/t7407-submodule-foreach.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2e14..03d2bd767d 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,6 +77,10 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -158,6 +162,10 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -176,6 +184,10 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 
@@ -223,6 +235,10 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
+	if test_have_prereq MINGW
+	then
+		dos2unix actual
+	fi &&
 	test_cmp expect actual
 '
 

From 3628d2a5f2402596e7561518dcc0450a73e86dbb Mon Sep 17 00:00:00 2001
From: Heiko Voigt 
Date: Wed, 16 Jun 2010 20:11:00 +0200
Subject: [PATCH 3638/3720] work around misdetection of stdin attached to a tty

Git on Windows was made aware of the fact that sometimes a file may be
used by another process and so an operation may fail but the user might
be able to fix it and is asking for confirmation whether it should
retry.

This is implemented in a way that git only asks in case stdin and stderr
are attached to a tty. Unfortunately this seems to be misdetected
sometimes causing the testsuite to hang when git is waiting for a user
answer.

This patch works around the situation.

Signed-off-by: Heiko Voigt 
---
 t/test-lib.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 9e2b71132a..32a74a6e7a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,6 +15,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
+# for git on windows so stdin will not be misdetected as attached to a
+# terminal
+exec < /dev/null
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 case "$GIT_TEST_TEE_STARTED, $* " in

From 936bc5399e2bdb851641bce57d40b1d516fe6988 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 8 Jan 2011 17:02:17 +0100
Subject: [PATCH 3639/3720] Handle new t1501 test case properly with MinGW

Signed-off-by: Johannes Schindelin 
---
 t/t1501-worktree.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 8f36aa9fc4..06982bddb7 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -339,6 +339,10 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
 	git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_have_prereq MINGW &&
+# make sure to test DOS path on Windows
+TRASH_DIRECTORY="$(cd "$TRASH_DIRECTORY" && pwd)"
+
 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
 	GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
 	test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&

From 3eca58450f544cb2fbfbdc3d8e51b12f5406b844 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 1 Apr 2011 09:29:35 +0200
Subject: [PATCH 3640/3720] MinGW: Skip test redirecting to fd 4

... because that does not work in MinGW.

Signed-off-by: Johannes Schindelin 
---
 t/t0081-line-buffer.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
index bd83ed371a..25dba008f3 100755
--- a/t/t0081-line-buffer.sh
+++ b/t/t0081-line-buffer.sh
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
 	test_cmp expect actual
 '
 
-test_expect_success 'read from file descriptor' '
+test_expect_success NOT_MINGW 'read from file descriptor' '
 	rm -f input &&
 	echo hello >expect &&
 	echo hello >input &&

From 87bba78ce2cffd21ad3f2bca1008e575d30f599c Mon Sep 17 00:00:00 2001
From: Pat Thoyts 
Date: Tue, 26 Apr 2011 10:39:30 +0100
Subject: [PATCH 3641/3720] t3102: Windows filesystems may not use a literal
 asterisk in filenames.

Exclude these tests when using MINGW.

Signed-off-by: Pat Thoyts 
---
 t/t3102-ls-tree-wildcards.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index c286854485..766af3de9b 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -4,14 +4,14 @@ test_description='ls-tree with(out) globs'
 
 . ./test-lib.sh
 
-test_expect_success 'setup' '
+test_expect_success NOT_MINGW 'setup' '
 	mkdir a aa "a[a]" &&
 	touch a/one aa/two "a[a]/three" &&
 	git add a/one aa/two "a[a]/three" &&
 	git commit -m test
 '
 
-test_expect_success 'ls-tree a[a] matches literally' '
+test_expect_success NOT_MINGW 'ls-tree a* matches literally' '
 	cat >expected <
Date: Sun, 1 May 2011 14:47:09 +0100
Subject: [PATCH 3642/3720] t5407: Fix line-ending dependency in
 post-rewrite.args

On msysGit creating the post-rewrite.args file using 'echo' has different
line endings from the expected comparison. Using perl normalizes the line
endings for each generated file.

Signed-off-by: Pat Thoyts 
---
 t/t5407-post-rewrite-hook.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670cea5..35403b435e 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -20,9 +20,13 @@ test_expect_success 'setup' '
 mkdir .git/hooks
 
 cat >.git/hooks/post-rewrite < "$TRASH_DIRECTORY"/post-rewrite.args
-cat > "$TRASH_DIRECTORY"/post-rewrite.data
+#!/usr/bin/perl
+open (AR, ">$TRASH_DIRECTORY/post-rewrite.args");
+print AR \$_,"\n" foreach @ARGV;
+open (DAT, ">$TRASH_DIRECTORY/post-rewrite.data");
+while() {
+       print DAT;
+}
 EOF
 chmod u+x .git/hooks/post-rewrite
 

From 38a0d3fb09f84e1190ad9ef5adc4647ae11cef48 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 5 Jan 2012 17:55:00 -0600
Subject: [PATCH 3643/3720] t030[02]: work around CR/LF issue

It is the old shell-script issue we had in a few other tests already.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 4a37cd79e5..66dc4fd6c9 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,6 +9,10 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
+	if test_have_prereq MINGW
+	then
+		dos2unix stderr
+	fi &&
 	test_cmp expect-stderr stderr
 }
 

From 6ce5f3c48d0a96255464fbe70b62b03ec37d1590 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 15:54:04 +0200
Subject: [PATCH 3644/3720] t9350: point out that refs are not updated
 correctly

This happens only when the corresponding commits are not exported in
the current fast-export run. This can happen either when the relevant
commit is already marked, or when the commit is explicitly marked
as UNINTERESTING with a negative ref by another argument.

This breaks fast-export basec remote helpers.

Signed-off-by: Sverre Rabbelier 
---
 t/t9350-fast-export.sh | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index b00196bd23..57569a7eed 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -440,4 +440,15 @@ test_expect_success 'fast-export quotes pathnames' '
 	)
 '
 
+cat > expected << EOF
+reset refs/heads/master
+from $(git rev-parse master)
+
+EOF
+
+test_expect_failure 'refs are updated even if no commits need to be exported' '
+	git fast-export master..master > actual &&
+	test_cmp expected actual
+'
+
 test_done

From 341304b2ec8889b6e41184b39a7a7cfd613960d2 Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Sat, 3 Mar 2012 19:53:38 +0100
Subject: [PATCH 3645/3720] t5800: clarify skip message

The skip message takes about remote-hg while the tests are about the
general remote helper framework (and don't require hg). Correct the
message.
---
 t/t5800-remote-helpers.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 5702334510..d1fecda1d2 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -8,7 +8,7 @@ test_description='Test remote-helper import and export commands'
 . ./test-lib.sh
 
 if ! test_have_prereq PYTHON ; then
-	skip_all='skipping git-remote-hg tests, python not available'
+	skip_all='skipping remote helper tests, python not available'
 	test_done
 fi
 
@@ -17,7 +17,7 @@ import sys
 if sys.hexversion < 0x02040000:
     sys.exit(1)
 ' || {
-	skip_all='skipping git-remote-hg tests, python version < 2.4'
+	skip_all='skipping remote helper tests, python version < 2.4'
 	test_done
 }
 

From 669b07c7cbb410c544b6b12931a6a112580eac4f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 21:09:49 -0500
Subject: [PATCH 3646/3720] Windows: make sure that merge-octopus only outputs
 LF line endings

This happens to shut up t7602 on Windows which would otherwise take
the different line endings for a sign that the merge failed.

Signed-off-by: Johannes Schindelin 
---
 git-merge-octopus.sh | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh
index 8643f74cb0..2226eeba99 100755
--- a/git-merge-octopus.sh
+++ b/git-merge-octopus.sh
@@ -71,7 +71,9 @@ do
 
 	case "$LF$common$LF" in
 	*"$LF$SHA1$LF"*)
-		echo "Already up-to-date with $pretty_name"
+		cat << EOF
+Already up-to-date with $pretty_name
+EOF
 		continue
 		;;
 	esac
@@ -83,7 +85,9 @@ do
 		# tree as the intermediate result of the merge.
 		# We still need to count this as part of the parent set.
 
-		echo "Fast-forwarding to: $pretty_name"
+		cat << EOF
+Fast-forwarding to: $pretty_name
+EOF
 		git read-tree -u -m $head $SHA1 || exit
 		MRC=$SHA1 MRT=$(git write-tree)
 		continue
@@ -91,7 +95,9 @@ do
 
 	NON_FF_MERGE=1
 
-	echo "Trying simple merge with $pretty_name"
+	cat << EOF
+Trying simple merge with $pretty_name
+EOF
 	git read-tree -u -m --aggressive  $common $MRT $SHA1 || exit 2
 	next=$(git write-tree 2>/dev/null)
 	if test $? -ne 0

From 31f9c4f00b11cc22a436823aa0fa168700bc20bf Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 19 Apr 2012 18:21:29 -0500
Subject: [PATCH 3647/3720] Introduce and use test_cmp_text

On Windows, we suffer from frequently leaked DOS line endings. Let's
ignore them.

Signed-off-by: Johannes Schindelin 
---
 t/lib-credential.sh          |  6 +-----
 t/t7407-submodule-foreach.sh | 26 +++-----------------------
 t/t9001-send-email.sh        | 31 +++++++++++++++----------------
 t/test-lib.sh                | 14 +++++++++++++-
 4 files changed, 32 insertions(+), 45 deletions(-)

diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 66dc4fd6c9..aac99ec6f5 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -9,11 +9,7 @@ check() {
 	read_chunk >expect-stderr &&
 	test-credential "$@" stdout 2>stderr &&
 	test_cmp expect-stdout stdout &&
-	if test_have_prereq MINGW
-	then
-		dos2unix stderr
-	fi &&
-	test_cmp expect-stderr stderr
+	test_cmp_text expect-stderr stderr
 }
 
 read_chunk() {
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 03d2bd767d..a91102115b 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -77,10 +77,6 @@ test_expect_success 'test basic "submodule foreach" usage' '
 		git config foo.bar zar &&
 		git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -162,10 +158,6 @@ test_expect_success 'test messages from "foreach --recursive"' '
 		cd clone2 &&
 		git submodule foreach --recursive "true" > ../actual
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
 	test_i18ncmp expect actual
 '
 
@@ -184,11 +176,7 @@ test_expect_success 'test "foreach --quiet --recursive"' '
 		cd clone2 &&
 		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 test_expect_success 'use "update --recursive" to checkout all submodules' '
@@ -235,11 +223,7 @@ test_expect_success 'test "status --recursive"' '
 		cd clone3 &&
 		git submodule status --recursive > ../actual
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 sed -e "/nested1 /s/.*/+$nested1sha1 nested1 (file2~1)/;/sub[1-3]/d" < expect > expect2
@@ -254,11 +238,7 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached
 		) &&
 		git submodule status --cached --recursive -- nested1 > ../actual
 	) &&
-	if test_have_prereq MINGW
-	then
-		dos2unix actual
-	fi &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 test_expect_success 'use "git clone --recursive" to checkout all submodules' '
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 8c12c65c72..8f7c9c4448 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -23,7 +23,6 @@ test_expect_success $PREREQ \
       echo do
       echo "  echo \"!\$a!\""
       echo "done >commandline\$output"
-      test_have_prereq MINGW && echo "dos2unix commandline\$output"
       echo "cat > msgtxt\$output"
       ) >fake.sendmail &&
      chmod +x ./fake.sendmail &&
@@ -97,7 +96,7 @@ EOF
 
 test_expect_success $PREREQ \
     'Verify commandline' \
-    'test_cmp expected commandline1'
+    'test_cmp_text expected commandline1'
 
 test_expect_success $PREREQ 'Send patches with --envelope-sender' '
     clean_fake_sendmail &&
@@ -117,7 +116,7 @@ EOF
 
 test_expect_success $PREREQ \
     'Verify commandline' \
-    'test_cmp expected commandline1'
+    'test_cmp_text expected commandline1'
 
 test_expect_success $PREREQ 'Send patches with --envelope-sender=auto' '
     clean_fake_sendmail &&
@@ -137,7 +136,7 @@ EOF
 
 test_expect_success $PREREQ \
     'Verify commandline' \
-    'test_cmp expected commandline1'
+    'test_cmp_text expected commandline1'
 
 test_expect_success $PREREQ 'setup expect' "
 cat >expected-show-all-headers <<\EOF
@@ -186,7 +185,7 @@ test_expect_success $PREREQ 'Show all headers' '
 		-e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
 		-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
 		>actual-show-all-headers &&
-	test_cmp expected-show-all-headers actual-show-all-headers
+	test_cmp_text expected-show-all-headers actual-show-all-headers
 '
 
 test_expect_success $PREREQ 'Prompting works' '
@@ -327,13 +326,13 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '
 		2>errors &&
 	# The first message is a reply to --in-reply-to
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual &&
-	test_cmp expect actual &&
+	test_cmp_text expect actual &&
 	# Second and subsequent messages are replies to the first one
 	sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual &&
-	test_cmp expect actual &&
+	test_cmp_text expect actual &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
@@ -348,13 +347,13 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
 		$patches $patches $patches \
 		2>errors &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual &&
-	test_cmp expect actual &&
+	test_cmp_text expect actual &&
 	sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual &&
-	test_cmp expect actual &&
+	test_cmp_text expect actual &&
 	sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt2 >expect &&
 	sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual &&
-	test_cmp expect actual
+	test_cmp_text expect actual
 '
 
 test_expect_success $PREREQ 'setup fake editor' '
@@ -426,7 +425,7 @@ test_suppression () {
 		-e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
 		-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
 		>actual-suppress-$1${2+"-$2"} &&
-	test_cmp expected-suppress-$1${2+"-$2"} actual-suppress-$1${2+"-$2"}
+	test_cmp_text expected-suppress-$1${2+"-$2"} actual-suppress-$1${2+"-$2"}
 }
 
 test_expect_success $PREREQ 'sendemail.cc set' '
@@ -1078,7 +1077,7 @@ test_expect_success $PREREQ 'asks about and fixes 8bit encodings' '
 	grep email-using-8bit stdout &&
 	grep "Which 8bit encoding" stdout &&
 	egrep "Content|MIME" msgtxt1 >actual &&
-	test_cmp actual content-type-decl
+	test_cmp_text actual content-type-decl
 '
 
 test_expect_success $PREREQ 'sendemail.8bitEncoding works' '
@@ -1089,7 +1088,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' '
 			--smtp-server="$(pwd)/fake.sendmail" \
 			email-using-8bit >stdout &&
 	egrep "Content|MIME" msgtxt1 >actual &&
-	test_cmp actual content-type-decl
+	test_cmp_text actual content-type-decl
 '
 
 test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
@@ -1101,7 +1100,7 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
 			--8bit-encoding=UTF-8 \
 			email-using-8bit >stdout &&
 	egrep "Content|MIME" msgtxt1 >actual &&
-	test_cmp actual content-type-decl
+	test_cmp_text actual content-type-decl
 '
 
 test_expect_success $PREREQ 'setup expect' '
@@ -1130,7 +1129,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
 			--8bit-encoding=UTF-8 \
 			email-using-8bit >stdout &&
 	grep "Subject" msgtxt1 >actual &&
-	test_cmp expected actual
+	test_cmp_text expected actual
 '
 
 # Note that the patches in this test are deliberately out of order; we
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 32a74a6e7a..8b6f59fecd 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -635,12 +635,24 @@ else
 	test_set_prereq C_LOCALE_OUTPUT
 fi
 
+# Use this instead of test_cmp to compare files that are expected to contain
+# text (and therefore it should not matter whether the line ends in an LF or
+# a CR/LF).
+test_cmp_text () {
+	if test_have_prereq MINGW
+	then
+		dos2unix "$1" &&
+		dos2unix "$2"
+	fi &&
+	test_cmp "$@"
+}
+
 # Use this instead of test_cmp to compare files that contain expected and
 # actual output from git commands that can be translated.  When running
 # under GETTEXT_POISON this pretends that the command produced expected
 # results.
 test_i18ncmp () {
-	test -n "$GETTEXT_POISON" || test_cmp "$@"
+	test -n "$GETTEXT_POISON" || test_cmp_text "$@"
 }
 
 # Use this instead of "grep expected-string actual" to see if the

From 4f44a7f38774d3c11a8289131729712f960d2246 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:00 +0000
Subject: [PATCH 3648/3720] Enable color output in Windows cmd.exe

Git requires the TERM environment variable to be set for all color*
settings. Simulate the TERM variable if it is not set (default on Windows).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index a9e23c4842..db42488a1d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1210,6 +1210,10 @@ char *mingw_getenv(const char *name)
 		if (!result)
 			result = getenv_cs("TEMP");
 	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
 	return result;
 }
 

From 6259b1d212670980384036bae62a647ac4e33a80 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:01 +0000
Subject: [PATCH 3649/3720] Support Unicode console output on Windows

WriteConsoleW seems to be the only way to reliably print unicode to the
console (without weird code page conversions).

Also redirects vfprintf to the winansi.c version.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h   |  2 ++
 compat/winansi.c | 26 ++++++++++++++++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 1e5ec25cdc..54fae7cdc6 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -291,9 +291,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 int winansi_fputs(const char *str, FILE *stream);
 int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
 int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int winansi_vfprintf(FILE *stream, const char *format, va_list list);
 #define fputs winansi_fputs
 #define printf(...) winansi_printf(__VA_ARGS__)
 #define fprintf(...) winansi_fprintf(__VA_ARGS__)
+#define vfprintf winansi_vfprintf
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index dedce2104e..abe0feaa2c 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -3,6 +3,7 @@
  */
 
 #include "../git-compat-util.h"
+#include 
 
 /*
  Functions to be wrapped:
@@ -10,6 +11,7 @@
 #undef printf
 #undef fprintf
 #undef fputs
+#undef vfprintf
 /* TODO: write */
 
 /*
@@ -46,6 +48,18 @@ static void init(void)
 	initialized = 1;
 }
 
+static int write_console(const char *str, size_t len)
+{
+	/* convert utf-8 to utf-16, write directly to console */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
+	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
+	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+
+	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
+
+	/* return original (utf-8 encoded) length */
+	return len;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -245,13 +259,15 @@ static int ansi_emulate(const char *str, FILE *stream)
 	int rv = 0;
 	const char *pos = str;
 
+	fflush(stream);
+
 	while (*pos) {
 		pos = strstr(str, "\033[");
 		if (pos) {
 			size_t len = pos - str;
 
 			if (len) {
-				size_t out_len = fwrite(str, 1, len, stream);
+				size_t out_len = write_console(str, len);
 				rv += out_len;
 				if (out_len < len)
 					return rv;
@@ -260,14 +276,12 @@ static int ansi_emulate(const char *str, FILE *stream)
 			str = pos + 2;
 			rv += 2;
 
-			fflush(stream);
-
 			pos = set_attr(str);
 			rv += pos - str;
 			str = pos;
 		} else {
-			rv += strlen(str);
-			fputs(str, stream);
+			size_t len = strlen(str);
+			rv += write_console(str, len);
 			return rv;
 		}
 	}
@@ -294,7 +308,7 @@ int winansi_fputs(const char *str, FILE *stream)
 		return EOF;
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 {
 	int len, rv;
 	char small_buf[256];

From ebef08c1daf94aea376ec2dae103c90f49958179 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:02 +0000
Subject: [PATCH 3650/3720] Detect console streams more reliably on Windows

GetStdHandle(STD_OUTPUT_HANDLE) doesn't work for stderr if stdout is
redirected. Use _get_osfhandle of the FILE* instead.

_isatty() is true for all character devices (including parallel and serial
ports). Check return value of GetConsoleScreenBufferInfo instead to
reliably detect console handles (also don't initialize internal state from
an uninitialized CONSOLE_SCREEN_BUFFER_INFO structure if the function
fails).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 50 +++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index abe0feaa2c..c4be401a6e 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -25,27 +25,39 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static FILE *last_stream = NULL;
 
-static void init(void)
+static int is_console(FILE *stream)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
+	HANDLE hcon;
 
 	static int initialized = 0;
-	if (initialized)
-		return;
 
-	console = GetStdHandle(STD_OUTPUT_HANDLE);
-	if (console == INVALID_HANDLE_VALUE)
-		console = NULL;
+	/* use cached value if stream hasn't changed */
+	if (stream == last_stream)
+		return console != NULL;
 
-	if (!console)
-		return;
+	last_stream = stream;
+	console = NULL;
 
-	GetConsoleScreenBufferInfo(console, &sbi);
-	attr = plain_attr = sbi.wAttributes;
-	negative = 0;
+	/* get OS handle of the stream */
+	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	if (hcon == INVALID_HANDLE_VALUE)
+		return 0;
 
-	initialized = 1;
+	/* check if its a handle to a console output screen buffer */
+	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+		return 0;
+
+	if (!initialized) {
+		attr = plain_attr = sbi.wAttributes;
+		negative = 0;
+		initialized = 1;
+	}
+
+	console = hcon;
+	return 1;
 }
 
 static int write_console(const char *str, size_t len)
@@ -292,12 +304,7 @@ int winansi_fputs(const char *str, FILE *stream)
 {
 	int rv;
 
-	if (!isatty(fileno(stream)))
-		return fputs(str, stream);
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		return fputs(str, stream);
 
 	rv = ansi_emulate(str, stream);
@@ -315,12 +322,7 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 	char *buf = small_buf;
 	va_list cp;
 
-	if (!isatty(fileno(stream)))
-		goto abort;
-
-	init();
-
-	if (!console)
+	if (!is_console(stream))
 		goto abort;
 
 	va_copy(cp, list);

From 66c99e3d3745660cb9ba20fef7e86c104c59e859 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 31 Jul 2010 00:04:03 +0000
Subject: [PATCH 3651/3720] Warn if the Windows console font doesn't support
 Unicode

Unicode console output won't display correctly with default settings
because the default console font ("Terminal") only supports the system's
OEM charset. Unfortunately, this is a user specific setting, so it cannot
be easily fixed by e.g. some registry tricks in the setup program.

This change prints a warning on exit if console output contained non-ascii
characters and the console font is supposedly not a TrueType font (which
usually have decent Unicode support).

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/compat/winansi.c b/compat/winansi.c
index c4be401a6e..a5ca2d9be3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,6 +4,8 @@
 
 #include "../git-compat-util.h"
 #include 
+#include 
+#include 
 
 /*
  Functions to be wrapped:
@@ -26,6 +28,54 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+
+typedef struct _CONSOLE_FONT_INFOEX {
+	ULONG cbSize;
+	DWORD nFont;
+	COORD dwFontSize;
+	UINT FontFamily;
+	UINT FontWeight;
+	WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+		PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+	DWORD fontFamily = 0;
+	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
+		return;
+
+	/* GetCurrentConsoleFontEx is available since Vista */
+	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
+	if (pGetCurrentConsoleFontEx) {
+		CONSOLE_FONT_INFOEX cfi;
+		cfi.cbSize = sizeof(cfi);
+		if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+			fontFamily = cfi.FontFamily;
+	} else {
+		/* pre-Vista: check default console font in registry */
+		HKEY hkey;
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
+				KEY_READ, &hkey)) {
+			DWORD size = sizeof(fontFamily);
+			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+					(LPVOID) &fontFamily, &size);
+			RegCloseKey(hkey);
+		}
+	}
+
+	if (!(fontFamily & TMPF_TRUETYPE))
+		warning("Your console font probably doesn\'t support "
+			"Unicode. If you experience strange characters in the output, "
+			"consider switching to a TrueType font such as Lucida Console!");
+}
 
 static int is_console(FILE *stream)
 {
@@ -54,6 +104,8 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
+		/* check console font on exit */
+		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -69,6 +121,10 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
+	/* remember if non-ascii characters are printed */
+	if (wlen != len)
+		non_ascii_used = 1;
+
 	/* return original (utf-8 encoded) length */
 	return len;
 }

From 4bcf43370c3a5341307092db3658a435b70efb99 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Tue, 3 Aug 2010 21:01:08 +0200
Subject: [PATCH 3652/3720] Give commit message reencoding for output on MinGW
 a chance

Signed-off-by: Johannes Schindelin 
---
 log-tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/log-tree.c b/log-tree.c
index 376d973176..2006f99650 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -678,7 +678,8 @@ void show_log(struct rev_info *opt)
 	if (opt->graph)
 		graph_show_commit_msg(opt->graph, &msgbuf);
 	else
-		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		/* Do not use fwrite() to give MinGW reencoding a chance */
+		printf("%.*s", (int)msgbuf.len, msgbuf.buf);
 	if (opt->use_terminator) {
 		if (!opt->missing_newline)
 			graph_show_padding(opt->graph);

From f889def83515142eac5a3e9c3f047e19bd0533c0 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:34:33 +0100
Subject: [PATCH 3653/3720] Win32 dirent: remove unused dirent.d_ino member

There are no proper inodes on Windows, so remove dirent.d_ino and #define
NO_D_INO_IN_DIRENT in the Makefile (this skips e.g. an ineffective qsort in
fsck.c).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 Makefile              | 2 ++
 compat/win32/dirent.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 38fb812d54..6f7382bade 100644
--- a/Makefile
+++ b/Makefile
@@ -1239,6 +1239,7 @@ ifeq ($(uname_S),Windows)
 	BLK_SHA1 = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
+	NO_D_INO_IN_DIRENT = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1331,6 +1332,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_INET_PTON = YesPlease
 	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
+	NO_D_INO_IN_DIRENT = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 927a25ca76..b38973b051 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,7 +9,6 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	long d_ino;                      /* Always zero. */
 	char d_name[FILENAME_MAX];       /* File name. */
 	union {
 		unsigned short d_reclen; /* Always zero. */

From db7eb1011b15d6c9920a46c259b8ad9bccbc504e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:38:25 +0100
Subject: [PATCH 3654/3720] Win32 dirent: remove unused dirent.d_reclen member

Remove the union around dirent.d_type and the unused dirent.d_reclen member
(which was necessary for compatibility with the MinGW dirent runtime, which
is no longer used).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index b38973b051..7f4e6c71d9 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,10 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	char d_name[FILENAME_MAX];       /* File name. */
-	union {
-		unsigned short d_reclen; /* Always zero. */
-		unsigned char  d_type;   /* Reimplementation adds this */
-	};
+	unsigned char d_type;      /* file type to prevent lstat after readdir */
 };
 
 DIR *opendir(const char *dirname);

From 7c918f6349fecf7683fa5e49096ddfabfb0cadbd Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:43:14 +0100
Subject: [PATCH 3655/3720] Win32 dirent: change FILENAME_MAX to MAX_PATH

FILENAME_MAX and MAX_PATH are both 260 on Windows, however, MAX_PATH is
used throughout the other Win32 code in Git, and also defines the length
of file name buffers in the Win32 API (e.g. WIN32_FIND_DATA.cFileName,
from which we're copying the dirent data).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 7f4e6c71d9..8838cd61fc 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -9,8 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-	char d_name[FILENAME_MAX];       /* File name. */
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
+	char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);

From 13f971b3b895dc5f6bc436efb20bc7e1c018d79a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:47:41 +0100
Subject: [PATCH 3656/3720] Win32 dirent: clarify #include directives

Git-compat-util.h is two dirs up, and already includes  (which
is the same as "dirent.h" due to -Icompat/win32 in the Makefile).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 7a0debe51b..fac7f25047 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -1,5 +1,4 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
 	struct dirent dd_dir; /* includes d_type */

From 4e16e23a2ae43ed5e110d8d5a1f61b3fcfdbe960 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:57:02 +0100
Subject: [PATCH 3657/3720] Win32 dirent: improve dirent implementation

Improve the dirent implementation by removing the relics that were once
necessary to plug into the now unused MinGW runtime, in preparation for
Unicode file name support.

Move FindFirstFile to opendir, and FindClose to closedir, with the
following implications:
- DIR.dd_name is no longer needed
- chdir(one); opendir(relative); chdir(two); readdir() works as expected
  (i.e. lists one/relative instead of two/relative)
- DIR.dd_handle is a valid handle for the entire lifetime of the DIR struct
- thus, all checks for dd_handle == INVALID_HANDLE_VALUE and dd_handle == 0
  have been removed
- the special case that the directory has been fully read (which was
  previously explicitly tracked with dd_handle == INVALID_HANDLE_VALUE &&
  dd_stat != 0) is now handled implicitly by the FindNextFile error
  handling code (if a client continues to call readdir after receiving
  NULL, FindNextFile will continue to fail with ERROR_NO_MORE_FILES, to
  the same effect)
- extracting dirent data from WIN32_FIND_DATA is needed in two places, so
  moved to its own method
- GetFileAttributes is no longer needed. The same information can be
  obtained from the FindFirstFile error code, which is ERROR_DIRECTORY if
  the name is NOT a directory (-> ENOTDIR), otherwise we can use
  err_win_to_posix (e.g. ERROR_PATH_NOT_FOUND -> ENOENT). The
  ERROR_DIRECTORY case could be fixed in err_win_to_posix, but this
  probably breaks other functionality.

Removes the ERROR_NO_MORE_FILES check after FindFirstFile (this was
fortunately a NOOP (searching for '*' always finds '.' and '..'),
otherwise the subsequent code would have copied data from an uninitialized
buffer).

Changes malloc to git support function xmalloc, so opendir will die() if
out of memory, rather than failing with ENOMEM and letting git work on
incomplete directory listings (error handling in dir.c is quite sparse).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/win32/dirent.c | 111 ++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index fac7f25047..82a515c21b 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -4,92 +4,88 @@ struct DIR {
 	struct dirent dd_dir; /* includes d_type */
 	HANDLE dd_handle;     /* FindFirstFile handle */
 	int dd_stat;          /* 0-based index */
-	char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+	/* copy file name from WIN32_FIND_DATA to dirent */
+	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+	/* Set file type, based on WIN32_FIND_DATA */
+	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		ent->d_type = DT_DIR;
+	else
+		ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-	DWORD attrs = GetFileAttributesA(name);
+	char pattern[MAX_PATH];
+	WIN32_FIND_DATAA fdata;
+	HANDLE h;
 	int len;
-	DIR *p;
+	DIR *dir;
 
-	/* check for valid path */
-	if (attrs == INVALID_FILE_ATTRIBUTES) {
-		errno = ENOENT;
+	/* check that name is not NULL */
+	if (!name) {
+		errno = EINVAL;
 		return NULL;
 	}
-
-	/* check if it's a directory */
-	if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-		errno = ENOTDIR;
-		return NULL;
-	}
-
 	/* check that the pattern won't be too long for FindFirstFileA */
 	len = strlen(name);
-	if (is_dir_sep(name[len - 1]))
-		len--;
 	if (len + 2 >= MAX_PATH) {
 		errno = ENAMETOOLONG;
 		return NULL;
 	}
+	/* copy name to temp buffer */
+	memcpy(pattern, name, len + 1);
 
-	p = malloc(sizeof(DIR) + len + 2);
-	if (!p)
+	/* append optional '/' and wildcard '*' */
+	if (len && !is_dir_sep(pattern[len - 1]))
+		pattern[len++] = '/';
+	pattern[len++] = '*';
+	pattern[len] = 0;
+
+	/* open find handle */
+	h = FindFirstFileA(pattern, &fdata);
+	if (h == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
 		return NULL;
+	}
 
-	memset(p, 0, sizeof(DIR) + len + 2);
-	strcpy(p->dd_name, name);
-	p->dd_name[len] = '/';
-	p->dd_name[len+1] = '*';
-
-	p->dd_handle = INVALID_HANDLE_VALUE;
-	return p;
+	/* initialize DIR structure and copy first dir entry */
+	dir = xmalloc(sizeof(DIR));
+	dir->dd_handle = h;
+	dir->dd_stat = 0;
+	finddata2dirent(&dir->dd_dir, &fdata);
+	return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-	WIN32_FIND_DATAA buf;
-	HANDLE handle;
-
-	if (!dir || !dir->dd_handle) {
+	if (!dir) {
 		errno = EBADF; /* No set_errno for mingw */
 		return NULL;
 	}
 
-	if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-		DWORD lasterr;
-		handle = FindFirstFileA(dir->dd_name, &buf);
-		lasterr = GetLastError();
-		dir->dd_handle = handle;
-		if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-			errno = err_win_to_posix(lasterr);
+	/* if first entry, dirent has already been set up by opendir */
+	if (dir->dd_stat) {
+		/* get next entry and convert from WIN32_FIND_DATA to dirent */
+		WIN32_FIND_DATAA fdata;
+		if (FindNextFileA(dir->dd_handle, &fdata)) {
+			finddata2dirent(&dir->dd_dir, &fdata);
+		} else {
+			DWORD lasterr = GetLastError();
+			/* POSIX says you shouldn't set errno when readdir can't
+			   find any more files; so, if another error we leave it set. */
+			if (lasterr != ERROR_NO_MORE_FILES)
+				errno = err_win_to_posix(lasterr);
 			return NULL;
 		}
-	} else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-		return NULL;
-	} else if (!FindNextFileA(dir->dd_handle, &buf)) {
-		DWORD lasterr = GetLastError();
-		FindClose(dir->dd_handle);
-		dir->dd_handle = INVALID_HANDLE_VALUE;
-		/* POSIX says you shouldn't set errno when readdir can't
-		   find any more files; so, if another error we leave it set. */
-		if (lasterr != ERROR_NO_MORE_FILES)
-			errno = err_win_to_posix(lasterr);
-		return NULL;
 	}
 
-	/* We get here if `buf' contains valid data.  */
-	strcpy(dir->dd_dir.d_name, buf.cFileName);
 	++dir->dd_stat;
-
-	/* Set file type, based on WIN32_FIND_DATA */
-	dir->dd_dir.d_type = 0;
-	if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		dir->dd_dir.d_type |= DT_DIR;
-	else
-		dir->dd_dir.d_type |= DT_REG;
-
 	return &dir->dd_dir;
 }
 
@@ -100,8 +96,7 @@ int closedir(DIR *dir)
 		return -1;
 	}
 
-	if (dir->dd_handle != INVALID_HANDLE_VALUE)
-		FindClose(dir->dd_handle);
+	FindClose(dir->dd_handle);
 	free(dir);
 	return 0;
 }

From 0022f3dc7a4a0d8399750af6807e5a5309869ee1 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 18:04:16 +0100
Subject: [PATCH 3658/3720] Win32: fix potential multi-threading issue

...by removing a static buffer in do_stat_internal.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index db42488a1d..24b4014cf0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -475,7 +475,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
 	int namelen;
-	static char alt_name[PATH_MAX];
+	char alt_name[PATH_MAX];
 
 	if (!do_lstat(follow, file_name, buf))
 		return 0;

From 44622fb684fbdfa2da334592dc105cdc99fd0fc0 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:47:23 +0100
Subject: [PATCH 3659/3720] Win32: move main macro to a function

The code in the MinGW main macro is getting more and more complex, move to
a separate initialization function for readabiliy and extensibility.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h | 14 ++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 24b4014cf0..0d6a351c98 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1877,3 +1877,18 @@ int mingw_offset_1st_component(const char *path)
 
 	return offset + is_dir_sep(path[offset]);
 }
+
+void mingw_startup()
+{
+	/* copy executable name to argv[0] */
+	__argv[0] = xstrdup(_pgmptr);
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index 54fae7cdc6..9f3741ad39 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -331,22 +331,16 @@ char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(); \
 int main(int argc, const char **argv) \
 { \
-	extern CRITICAL_SECTION pinfo_cs; \
-	_fmode = _O_BINARY; \
-	_setmode(_fileno(stdin), _O_BINARY); \
-	_setmode(_fileno(stdout), _O_BINARY); \
-	_setmode(_fileno(stderr), _O_BINARY); \
-	argv[0] = xstrdup(_pgmptr); \
-	InitializeCriticalSection(&pinfo_cs); \
-	return mingw_main(argc, argv); \
+	mingw_startup(); \
+	return mingw_main(__argc, __argv); \
 } \
 static int mingw_main(c,v)
 

From 96ea4c97f261a864d9b13839b95f95de4380782e Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 19:52:20 +0100
Subject: [PATCH 3660/3720] MinGW: disable CRT command line globbing

MingwRT listens to _CRT_glob to decide if __getmainargs should
perform globbing, with the default being that it should.
Unfortunately, __getmainargs globbing is sub-par; for instance
patterns like "*.c" will only match c-sources in the current
directory.

Disable __getmainargs' command line wildcard expansion, so these
patterns will be left untouched, and handled by Git's superior
built-in globbing instead.

MSVC defaults to no globbing, so we don't need to do anything
in that case.

This fixes t5505 and t7810.

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/mingw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 0d6a351c98..3767048a6d 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1878,6 +1878,12 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
 void mingw_startup()
 {
 	/* copy executable name to argv[0] */

From 20a9efa96100c0a84322cb0bdb06feb637ebc3e3 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 5 Aug 2010 22:45:33 +0000
Subject: [PATCH 3661/3720] Unicode console: fix font warning on Vista and Win7

GetCurrentConsoleFontEx in an atexit routine doesn't work because git
closes stdout before exit (which also closes the console handle). Check
the console font when we first encounter a non-ascii character and only
schedule the warning message to be printed at exit (warnings go to stderr,
which is not closed by git).

Signed-off-by: Karsten Blees 
Signed-off-by: Erik Faye-Lund 
---
 compat/winansi.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a5ca2d9be3..ab38ed95ab 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -28,7 +28,6 @@ static WORD plain_attr;
 static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
-static int non_ascii_used = 0;
 
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
@@ -42,14 +41,23 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void warn_if_raster_font(void)
+static void print_font_warning(void)
 {
+	warning("Your console font probably doesn\'t support Unicode. If "
+		"you experience strange characters in the output, consider "
+		"switching to a TrueType font such as Lucida Console!");
+}
+
+static void check_truetype_font(void)
+{
+	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't bother if output was ascii only */
-	if (!non_ascii_used)
+	/* don't do this twice */
+	if (truetype_font_checked)
 		return;
+	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
@@ -72,9 +80,7 @@ static void warn_if_raster_font(void)
 	}
 
 	if (!(fontFamily & TMPF_TRUETYPE))
-		warning("Your console font probably doesn\'t support "
-			"Unicode. If you experience strange characters in the output, "
-			"consider switching to a TrueType font such as Lucida Console!");
+		atexit(print_font_warning);
 }
 
 static int is_console(FILE *stream)
@@ -104,8 +110,6 @@ static int is_console(FILE *stream)
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
-		/* check console font on exit */
-		atexit(warn_if_raster_font);
 	}
 
 	console = hcon;
@@ -121,9 +125,12 @@ static int write_console(const char *str, size_t len)
 
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/* remember if non-ascii characters are printed */
+	/*
+	 * if non-ascii characters are printed, check that the current console
+	 * font supports this
+	 */
 	if (wlen != len)
-		non_ascii_used = 1;
+		check_truetype_font();
 
 	/* return original (utf-8 encoded) length */
 	return len;

From e402244e3f8d3414085923bc5246b7733deca8bb Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 19:06:41 +0100
Subject: [PATCH 3662/3720] Revert "Windows: teach getenv to do a
 case-sensitive search"

This reverts commit df599e9612788b728ce43a03159b85f1fe624d6a.

As of 5e9637c6 "i18n: add infrastructure for translating Git with gettext",
eval_gettext uses MinGW envsubst.exe instead of git-sh-i18n--envsubst.exe
for variable substitution. This breaks git-submodule.sh messages and tests,
as envsubst.exe doesn't support case-sensitive environment lookup (the same
is true for almost everything on Windows, including MSys and Cygwin tools).

30a615ac "Windows/i18n: rename $path to prevent clashes with $PATH" renames
the conflicting variable in git-submodule.sh, so that it works on Windows
(i.e. with case-insensitive environment, regardless of the toolset).

Revert to the documented behaviour of case-insensitive environment on
Windows.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 +++--------------------
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 3767048a6d..17ed1f7ad5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1184,31 +1184,14 @@ char **make_augmented_environ(const char *const *vars)
 }
 
 #undef getenv
-
-/*
- * The system's getenv looks up the name in a case-insensitive manner.
- * This version tries a case-sensitive lookup and falls back to
- * case-insensitive if nothing was found.  This is necessary because,
- * as a prominent example, CMD sets 'Path', but not 'PATH'.
- * Warning: not thread-safe.
- */
-static char *getenv_cs(const char *name)
-{
-	size_t len = strlen(name);
-	int i = lookup_env(environ, name, len);
-	if (i >= 0)
-		return environ[i] + len + 1;	/* skip past name and '=' */
-	return getenv(name);
-}
-
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv_cs(name);
+	char *result = getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv_cs("TMP");
+		result = getenv("TMP");
 		if (!result)
-			result = getenv_cs("TEMP");
+			result = getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */

From ee0b63f1d358e3212bac032a6848fc6cb5a207a6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:19:31 +0100
Subject: [PATCH 3663/3720] Revert "mingw.c: move definition of mingw_getenv
 down"

This reverts commit 06bc4b796ad69ba93f0a8c451368602e0553c2d3.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 17ed1f7ad5..e1f7a3b0b5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -180,7 +180,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	vsnprintf(question, sizeof(question), format, args);
 	va_end(args);
 
-	if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
+	if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
 		retry_hook[1] = question;
 		return !run_command_v_opt(retry_hook, 0);
 	}
@@ -665,6 +665,23 @@ char *mingw_getcwd(char *pointer, int len)
 	return ret;
 }
 
+#undef getenv
+char *mingw_getenv(const char *name)
+{
+	char *result = getenv(name);
+	if (!result && !strcmp(name, "TMPDIR")) {
+		/* on Windows it is TMP and TEMP */
+		result = getenv("TMP");
+		if (!result)
+			result = getenv("TEMP");
+	}
+	else if (!result && !strcmp(name, "TERM")) {
+		/* simulate TERM to enable auto-color (see color.c) */
+		result = "winansi";
+	}
+	return result;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -764,7 +781,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-	char *p, **path, *envpath = mingw_getenv("PATH");
+	char *p, **path, *envpath = getenv("PATH");
 	int i, n = 0;
 
 	if (!envpath || !*envpath)
@@ -1183,23 +1200,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-	char *result = getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
-		if (!result)
-			result = getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 1d690f0860dc0b846c7a65522741bcc56aafe3fd Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 6 Oct 2011 17:40:56 +0000
Subject: [PATCH 3664/3720] MSVC: fix winansi.c compile errors

Some constants (such as LF_FACESIZE) are undefined with -DNOGDI (set in the
Makefile), and CONSOLE_FONT_INFOEX is available in MSVC, but not in MinGW.

Cast FARPROC to PGETCURRENTCONSOLEFONTEX to suppress MSVC compiler warning.

Signed-off-by: Karsten Blees 
Signed-off-by: Johannes Schindelin 
---
 compat/winansi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index ab38ed95ab..bec6713b74 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -2,6 +2,7 @@
  * Copyright 2008 Peter Harris 
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
 #include 
 #include 
@@ -29,6 +30,7 @@ static WORD attr;
 static int negative;
 static FILE *last_stream = NULL;
 
+#ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
 	ULONG cbSize;
 	DWORD nFont;
@@ -37,6 +39,7 @@ typedef struct _CONSOLE_FONT_INFOEX {
 	UINT FontWeight;
 	WCHAR FaceName[LF_FACESIZE];
 } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
 
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
@@ -60,8 +63,8 @@ static void check_truetype_font(void)
 	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
-	pGetCurrentConsoleFontEx = GetProcAddress(GetModuleHandle("kernel32.dll"),
-			"GetCurrentConsoleFontEx");
+	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);

From dc7c18e038c0a287404beb8d537097ef00eb2f59 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:24:19 +0100
Subject: [PATCH 3665/3720] Win32: Thread-safe windows console output

Winansi.c has many static variables that are accessed and modified from
the [v][f]printf / fputs functions overridden in the file. This may cause
multi threaded git commands that print to the console to produce corrupted
output or even crash.

Additionally, winansi.c doesn't override all functions that can be used to
print to the console (e.g. fwrite, write, fputc are missing), so that ANSI
escapes don't work properly for some git commands (e.g. git-grep).

Instead of doing ANSI emulation in just a few wrapped functions on top of
the IO API, let's plug into the IO system and take advantage of the thread
safety inherent to the IO system.

Redirect stdout and stderr to a pipe if they point to the console. A
background thread reads from the pipe, handles ANSI escape sequences and
UTF-8 to UTF-16 conversion, then writes to the console.

The pipe-based stdout and stderr replacements must be set to unbuffered, as
MSVCRT doesn't support line buffering and fully buffered streams are
inappropriate for console output.

Due to the byte-oriented pipe, ANSI escape sequences and multi-byte UTF-8
sequences can no longer be expected to arrive in one piece. Replace the
string-based ansi_emulate() with a simple stateful parser (this also fixes
colored diff hunk headers, which were broken as of commit 2efcc977).

Override isatty to return true for the pipes redirecting to the console.

Exec/spawn obtain the original console handle to pass to the next process
via winansi_get_osfhandle().

All other overrides are gone, the default stdio implementations work as
expected with the piped stdout/stderr descriptors.

Global variables are either initialized on startup (single threaded) or
exclusively modified by the background thread. Threads communicate through
the pipe, no further synchronization is necessary.

The background thread is terminated by disonnecting the pipe after flushing
the stdio and pipe buffers. This doesn't work for anonymous pipes (created
via CreatePipe), as DisconnectNamedPipe only works on the read end, which
discards remaining data. Thus we have to setup the pipe manually, with the
write end beeing the server (opened with CreateNamedPipe) and the read end
the client (opened with CreateFile).

Limitations: doesn't track reopened or duped file descriptors, i.e.:
- fdopen(1/2) returns fully buffered streams
- dup(1/2), dup2(1/2) returns normal pipe descriptors (i.e. isatty() =
  false, winansi_get_osfhandle won't return the original console handle)

Currently, only the git-format-patch command uses xfdopen(xdup(1)) (see
"realstdout" in builtin/log.c), but works well with these limitations.

Many thanks to Atsushi Nakagawa  for suggesting and
reviewing the thread-exit-mechanism.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c   |   9 +-
 compat/mingw.h   |  12 +-
 compat/winansi.c | 420 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 282 insertions(+), 159 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index e1f7a3b0b5..ee37201815 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -917,9 +917,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	memset(&si, 0, sizeof(si));
 	si.cb = sizeof(si);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-	si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-	si.hStdError = (HANDLE) _get_osfhandle(fherr);
+	si.hStdInput = winansi_get_osfhandle(fhin);
+	si.hStdOutput = winansi_get_osfhandle(fhout);
+	si.hStdError = winansi_get_osfhandle(fherr);
 
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
@@ -1880,4 +1880,7 @@ void mingw_startup()
 	_setmode(_fileno(stdin), _O_BINARY);
 	_setmode(_fileno(stdout), _O_BINARY);
 	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
 }
diff --git a/compat/mingw.h b/compat/mingw.h
index 9f3741ad39..956bfa795b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -288,14 +288,10 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-int winansi_vfprintf(FILE *stream, const char *format, va_list list);
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
-#define vfprintf winansi_vfprintf
+void winansi_init(void);
+int winansi_isatty(int fd);
+HANDLE winansi_get_osfhandle(int fd);
+#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index bec6713b74..a3e4d88295 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -4,18 +4,13 @@
 
 #undef NOGDI
 #include "../git-compat-util.h"
-#include 
 #include 
 #include 
 
 /*
  Functions to be wrapped:
 */
-#undef printf
-#undef fprintf
-#undef fputs
-#undef vfprintf
-/* TODO: write */
+#undef isatty
 
 /*
  ANSI codes used by git: m, K
@@ -28,7 +23,10 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
-static FILE *last_stream = NULL;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hwrite1 = INVALID_HANDLE_VALUE, hwrite2 = INVALID_HANDLE_VALUE;
+static HANDLE hconsole1, hconsole2;
 
 #ifdef __MINGW32__
 typedef struct _CONSOLE_FONT_INFOEX {
@@ -44,27 +42,19 @@ typedef struct _CONSOLE_FONT_INFOEX {
 typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
 		PCONSOLE_FONT_INFOEX);
 
-static void print_font_warning(void)
+static void warn_if_raster_font(void)
 {
-	warning("Your console font probably doesn\'t support Unicode. If "
-		"you experience strange characters in the output, consider "
-		"switching to a TrueType font such as Lucida Console!");
-}
-
-static void check_truetype_font(void)
-{
-	static int truetype_font_checked;
 	DWORD fontFamily = 0;
 	PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
 
-	/* don't do this twice */
-	if (truetype_font_checked)
+	/* don't bother if output was ascii only */
+	if (!non_ascii_used)
 		return;
-	truetype_font_checked = 1;
 
 	/* GetCurrentConsoleFontEx is available since Vista */
 	pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
+			GetModuleHandle("kernel32.dll"),
+			"GetCurrentConsoleFontEx");
 	if (pGetCurrentConsoleFontEx) {
 		CONSOLE_FONT_INFOEX cfi;
 		cfi.cbSize = sizeof(cfi);
@@ -73,8 +63,8 @@ static void check_truetype_font(void)
 	} else {
 		/* pre-Vista: check default console font in registry */
 		HKEY hkey;
-		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
-				KEY_READ, &hkey)) {
+		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+				0, KEY_READ, &hkey)) {
 			DWORD size = sizeof(fontFamily);
 			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
 					(LPVOID) &fontFamily, &size);
@@ -82,61 +72,63 @@ static void check_truetype_font(void)
 		}
 	}
 
-	if (!(fontFamily & TMPF_TRUETYPE))
-		atexit(print_font_warning);
+	if (!(fontFamily & TMPF_TRUETYPE)) {
+		const wchar_t *msg = L"\nWarning: Your console font probably "
+			L"doesn\'t support Unicode. If you experience strange "
+			L"characters in the output, consider switching to a "
+			L"TrueType font such as Lucida Console!\n";
+		WriteConsoleW(console, msg, wcslen(msg), NULL, NULL);
+	}
 }
 
-static int is_console(FILE *stream)
+static int is_console(int fd)
 {
 	CONSOLE_SCREEN_BUFFER_INFO sbi;
 	HANDLE hcon;
 
 	static int initialized = 0;
 
-	/* use cached value if stream hasn't changed */
-	if (stream == last_stream)
-		return console != NULL;
-
-	last_stream = stream;
-	console = NULL;
-
-	/* get OS handle of the stream */
-	hcon = (HANDLE) _get_osfhandle(_fileno(stream));
+	/* get OS handle of the file descriptor */
+	hcon = (HANDLE) _get_osfhandle(fd);
 	if (hcon == INVALID_HANDLE_VALUE)
 		return 0;
 
+	/* check if its a device (i.e. console, printer, serial port) */
+	if (GetFileType(hcon) != FILE_TYPE_CHAR)
+		return 0;
+
 	/* check if its a handle to a console output screen buffer */
 	if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
+	/* initialize attributes */
 	if (!initialized) {
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
 	}
 
-	console = hcon;
 	return 1;
 }
 
-static int write_console(const char *str, size_t len)
-{
-	/* convert utf-8 to utf-16, write directly to console */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
-	wchar_t *wbuf = (wchar_t *) alloca(wlen * sizeof(wchar_t));
-	MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
 
+static void write_console(unsigned char *str, size_t len)
+{
+	/* only called from console_thread, so a static buffer will do */
+	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+
+	/* convert utf-8 to utf-16 */
+	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
+			ARRAY_SIZE(wbuf));
+
+	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);
 
-	/*
-	 * if non-ascii characters are printed, check that the current console
-	 * font supports this
-	 */
+	/* remember if non-ascii characters are printed */
 	if (wlen != len)
-		check_truetype_font();
-
-	/* return original (utf-8 encoded) length */
-	return len;
+		non_ascii_used = 1;
 }
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
@@ -182,18 +174,13 @@ static void erase_in_line(void)
 		&dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-	const char *func;
-	size_t len = strspn(str, "0123456789;");
-	func = str + len;
-
-	switch (*func) {
+	int i;
+	switch (func) {
 	case 'm':
-		do {
-			long val = strtol(str, (char **)&str, 10);
-			switch (val) {
+		for (i = 0; i < paramlen; i++) {
+			switch (params[i]) {
 			case 0: /* reset */
 				attr = plain_attr;
 				negative = 0;
@@ -316,9 +303,7 @@ static const char *set_attr(const char *str)
 				/* Unsupported code */
 				break;
 			}
-			str++;
-		} while (*(str-1) == ';');
-
+		}
 		set_console_attr();
 		break;
 	case 'K':
@@ -328,112 +313,251 @@ static const char *set_attr(const char *str)
 		/* Unsupported code */
 		break;
 	}
-
-	return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+	TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-	int rv = 0;
-	const char *pos = str;
+	unsigned char buffer[BUFFER_SIZE];
+	DWORD bytes;
+	int start, end = 0, c, parampos = 0, state = TEXT;
+	int params[MAX_PARAMS];
 
-	fflush(stream);
+	while (1) {
+		/* read next chunk of bytes from the pipe */
+		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+				NULL)) {
+			/* exit if pipe has been closed or disconnected */
+			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+					GetLastError() == ERROR_BROKEN_PIPE)
+				break;
+			/* ignore other errors */
+			continue;
+		}
 
-	while (*pos) {
-		pos = strstr(str, "\033[");
-		if (pos) {
-			size_t len = pos - str;
+		/* scan the bytes and handle ANSI control codes */
+		bytes += end;
+		start = end = 0;
+		while (end < bytes) {
+			c = buffer[end++];
+			switch (state) {
+			case TEXT:
+				if (c == ESCAPE) {
+					/* print text seen so far */
+					if (end - 1 > start)
+						write_console(buffer + start,
+							end - 1 - start);
 
-			if (len) {
-				size_t out_len = write_console(str, len);
-				rv += out_len;
-				if (out_len < len)
-					return rv;
+					/* then start parsing escape sequence */
+					start = end - 1;
+					memset(params, 0, sizeof(params));
+					parampos = 0;
+					state = ESCAPE;
+				}
+				break;
+
+			case ESCAPE:
+				/* continue if "\033[", otherwise bail out */
+				state = (c == BRACKET) ? BRACKET : TEXT;
+				break;
+
+			case BRACKET:
+				/* parse [0-9;]* into array of parameters */
+				if (c >= '0' && c <= '9') {
+					params[parampos] *= 10;
+					params[parampos] += c - '0';
+				} else if (c == ';') {
+					/*
+					 * next parameter, bail out if out of
+					 * bounds
+					 */
+					parampos++;
+					if (parampos >= MAX_PARAMS)
+						state = TEXT;
+				} else {
+					/*
+					 * end of escape sequence, change
+					 * console attributes
+					 */
+					set_attr(c, params, parampos + 1);
+					start = end;
+					state = TEXT;
+				}
+				break;
+			}
+		}
+
+		/* print remaining text unless parsing an escape sequence */
+		if (state == TEXT && end > start) {
+			/* check for incomplete UTF-8 sequences and fix end */
+			if (buffer[end - 1] >= 0x80) {
+				if (buffer[end -1] >= 0xc0)
+					end--;
+				else if (end - 1 > start &&
+						buffer[end - 2] >= 0xe0)
+					end -= 2;
+				else if (end - 2 > start &&
+						buffer[end - 3] >= 0xf0)
+					end -= 3;
 			}
 
-			str = pos + 2;
-			rv += 2;
+			/* print remaining complete UTF-8 sequences */
+			if (end > start)
+				write_console(buffer + start, end - start);
 
-			pos = set_attr(str);
-			rv += pos - str;
-			str = pos;
+			/* move remaining bytes to the front */
+			if (end < bytes)
+				memmove(buffer, buffer + end, bytes - end);
+			end = bytes - end;
 		} else {
-			size_t len = strlen(str);
-			rv += write_console(str, len);
-			return rv;
+			/* all data has been consumed, mark buffer empty */
+			end = 0;
 		}
 	}
-	return rv;
+
+	/* check if the console font supports unicode */
+	warn_if_raster_font();
+
+	CloseHandle(hread);
+	return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-	int rv;
+	/* flush all streams */
+	_flushall();
 
-	if (!is_console(stream))
-		return fputs(str, stream);
+	/* signal console thread to exit */
+	FlushFileBuffers(hwrite);
+	DisconnectNamedPipe(hwrite);
 
-	rv = ansi_emulate(str, stream);
+	/* wait for console thread to copy remaining data */
+	WaitForSingleObject(hthread, INFINITE);
 
-	if (rv >= 0)
-		return 0;
+	/* cleanup handles... */
+	if (hwrite1 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite1);
+	if (hwrite2 != INVALID_HANDLE_VALUE)
+		CloseHandle(hwrite2);
+	CloseHandle(hwrite);
+	CloseHandle(hthread);
+}
+
+static void die_lasterr(const char *fmt, ...)
+{
+	va_list params;
+	va_start(params, fmt);
+	errno = err_win_to_posix(GetLastError());
+	die_errno(fmt, params);
+	va_end(params);
+}
+
+static HANDLE duplicate_handle(HANDLE hnd)
+{
+	HANDLE hresult, hproc = GetCurrentProcess();
+	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+			DUPLICATE_SAME_ACCESS))
+		die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+	return hresult;
+}
+
+static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+{
+	/* get original console handle */
+	int fd = _fileno(stream);
+	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
+	if (hcon == INVALID_HANDLE_VALUE)
+		die_errno("_get_osfhandle(%i) failed", fd);
+
+	/* save a copy to phcon and console (used by the background thread) */
+	console = *phcon = duplicate_handle(hcon);
+
+	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
+	if (_dup2(new_fd, fd))
+		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+
+	/* no buffering, or stdout / stderr will be out of sync */
+	setbuf(stream, NULL);
+	return (HANDLE) _get_osfhandle(fd);
+}
+
+void winansi_init(void)
+{
+	int con1, con2, hwrite_fd;
+	char name[32];
+
+	/* check if either stdout or stderr is a console output screen buffer */
+	con1 = is_console(1);
+	con2 = is_console(2);
+	if (!con1 && !con2)
+		return;
+
+	/* create a named pipe to communicate with the console thread */
+	sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+	hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+	if (hwrite == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateNamedPipe failed");
+
+	hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (hread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateFile for named pipe failed");
+
+	/* start console spool thread on the pipe's read end */
+	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+	if (hthread == INVALID_HANDLE_VALUE)
+		die_lasterr("CreateThread(console_thread) failed");
+
+	/* schedule cleanup routine */
+	if (atexit(winansi_exit))
+		die_errno("atexit(winansi_exit) failed");
+
+	/* create a file descriptor for the write end of the pipe */
+	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
+	if (hwrite_fd == -1)
+		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
+
+	/* redirect stdout / stderr to the pipe */
+	if (con1)
+		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+	if (con2)
+		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
+
+	/* close pipe file descriptor (also closes the duped hwrite) */
+	close(hwrite_fd);
+}
+
+static int is_same_handle(HANDLE hnd, int fd)
+{
+	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
+}
+
+/*
+ * Return true if stdout / stderr is a pipe redirecting to the console.
+ */
+int winansi_isatty(int fd)
+{
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return 1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return 1;
 	else
-		return EOF;
+		return isatty(fd);
 }
 
-int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-	int len, rv;
-	char small_buf[256];
-	char *buf = small_buf;
-	va_list cp;
-
-	if (!is_console(stream))
-		goto abort;
-
-	va_copy(cp, list);
-	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-	va_end(cp);
-
-	if (len > sizeof(small_buf) - 1) {
-		buf = malloc(len + 1);
-		if (!buf)
-			goto abort;
-
-		len = vsnprintf(buf, len + 1, format, list);
-	}
-
-	rv = ansi_emulate(buf, stream);
-
-	if (buf != small_buf)
-		free(buf);
-	return rv;
-
-abort:
-	rv = vfprintf(stream, format, list);
-	return rv;
-}
-
-int winansi_fprintf(FILE *stream, const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stream, format, list);
-	va_end(list);
-
-	return rv;
-}
-
-int winansi_printf(const char *format, ...)
-{
-	va_list list;
-	int rv;
-
-	va_start(list, format);
-	rv = winansi_vfprintf(stdout, format, list);
-	va_end(list);
-
-	return rv;
+	if (fd == 1 && is_same_handle(hwrite1, 1))
+		return hconsole1;
+	else if (fd == 2 && is_same_handle(hwrite2, 2))
+		return hconsole2;
+	else
+		return (HANDLE) _get_osfhandle(fd);
 }

From e91461ed18b0764e8606d610c28f60715ea1ce39 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:05:06 +0100
Subject: [PATCH 3666/3720] Win32: add Unicode conversion functions

Add Unicode conversion functions to convert between Windows native UTF-16LE
encoding to UTF-8 and back.

To support repositories with legacy-encoded file names, the UTF-8 to UTF-16
conversion function tries to create valid, unique file names even for
invalid UTF-8 byte sequences, so that these repositories can be checked out
without error.

The current implementation leaves invalid UTF-8 bytes in range 0xa0 - 0xff
as is (producing printable Unicode chars \u00a0 - \u00ff, equivalent to
ISO-8859-1), and converts 0x80 - 0x9f to hex-code (\u0080 - \u009f are
control chars).

The Windows MultiByteToWideChar API was not used as it either drops invalid
UTF-8 sequences (on Win2k/XP; producing non-unique or even empty file
names) or converts them to the replacement char \ufffd (Vista/7; causing
ERROR_INVALID_NAME in subsequent calls to file system APIs).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c |  85 ++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index ee37201815..9cd188e170 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1861,6 +1861,91 @@ int mingw_offset_1st_component(const char *path)
 	return offset + is_dir_sep(path[offset]);
 }
 
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
diff --git a/compat/mingw.h b/compat/mingw.h
index 956bfa795b..661455efb2 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -326,6 +326,110 @@ void mingw_mark_as_git_dir(const char *dir);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A replacement of main() that adds win32 specific initialization.
  */

From 80fa4b6b8fe8a280c3ec4341e2757a2101a18528 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 18:21:28 +0100
Subject: [PATCH 3667/3720] Win32: Unicode file name support (except dirent)

Replaces Windows "ANSI" APIs dealing with file- or path names with their
Unicode equivalent, adding UTF-8/UTF-16LE conversion as necessary.

The dirent API (opendir/readdir/closedir) is updated in a separate commit.

Adds trivial wrappers for access, chmod and chdir.

Adds wrapper for mktemp (needed for both mkstemp and mkdtemp).

The simplest way to convert a repository with legacy-encoded (e.g. Cp1252)
file names to UTF-8 ist to checkout with an old msysgit version and
"git add --all & git commit" with the new version.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 210 ++++++++++++++++++++++++++++++++++---------------
 compat/mingw.h |  13 +++
 2 files changed, 158 insertions(+), 65 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9cd188e170..d81e9c02c1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "win32.h"
 #include 
+#include 
 #include "../strbuf.h"
 #include "../run-command.h"
 #include "../cache.h"
@@ -200,14 +201,16 @@ static int ask_yes_no_if_possible(const char *format, ...)
 	}
 }
 
-#undef unlink
 int mingw_unlink(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
 	/* read-only files cannot be removed */
-	chmod(pathname, 0666);
-	while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
 		/*
@@ -223,43 +226,40 @@ int mingw_unlink(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = unlink(pathname);
+	       ret = _wunlink(wpathname);
 	return ret;
 }
 
-static int is_dir_empty(const char *path)
+static int is_dir_empty(const wchar_t *wpath)
 {
-	struct strbuf buf = STRBUF_INIT;
-	WIN32_FIND_DATAA findbuf;
+	WIN32_FIND_DATAW findbuf;
 	HANDLE handle;
-
-	strbuf_addf(&buf, "%s\\*", path);
-	handle = FindFirstFileA(buf.buf, &findbuf);
-	if (handle == INVALID_HANDLE_VALUE) {
-		strbuf_release(&buf);
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
 		return GetLastError() == ERROR_NO_MORE_FILES;
-	}
 
-	while (!strcmp(findbuf.cFileName, ".") ||
-			!strcmp(findbuf.cFileName, ".."))
-		if (!FindNextFile(handle, &findbuf)) {
-			strbuf_release(&buf);
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf))
 			return GetLastError() == ERROR_NO_MORE_FILES;
-		}
 	FindClose(handle);
-	strbuf_release(&buf);
 	return 0;
 }
 
-#undef rmdir
 int mingw_rmdir(const char *pathname)
 {
 	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
 
-	while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
 		if (!is_file_in_use_error(GetLastError()))
 			break;
-		if (!is_dir_empty(pathname)) {
+		if (!is_dir_empty(wpathname)) {
 			errno = ENOTEMPTY;
 			break;
 		}
@@ -276,14 +276,14 @@ int mingw_rmdir(const char *pathname)
 	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
 	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
 			"Should I try again?", pathname))
-	       ret = rmdir(pathname);
+	       ret = _wrmdir(wpathname);
 	return ret;
 }
 
-static int make_hidden(const char *path)
+static int make_hidden(const wchar_t *path)
 {
-	DWORD attribs = GetFileAttributes(path);
-	if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs))
+	DWORD attribs = GetFileAttributesW(path);
+	if (SetFileAttributesW(path, FILE_ATTRIBUTE_HIDDEN | attribs))
 		return 0;
 	errno = err_win_to_posix(GetLastError());
 	return -1;
@@ -291,19 +291,23 @@ static int make_hidden(const char *path)
 
 void mingw_mark_as_git_dir(const char *dir)
 {
-	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() &&
-	    make_hidden(dir))
-		warning("Failed to make '%s' hidden", dir);
+	wchar_t wdir[MAX_PATH];
+	if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository())
+		if (xutftowcs_path(wdir, dir) < 0 || make_hidden(wdir))
+			warning("Failed to make '%s' hidden", dir);
 	git_config_set("core.hideDotFiles",
 		hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" :
 		(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ?
 		 "dotGitOnly" : "true"));
 }
 
-#undef mkdir
 int mingw_mkdir(const char *path, int mode)
 {
-	int ret = mkdir(path);
+	int ret;
+	wchar_t wpath[MAX_PATH];
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
 	if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) {
 		/*
 		 * In Windows a file or dir starting with a dot is not
@@ -312,17 +316,17 @@ int mingw_mkdir(const char *path, int mode)
 		 */
 		const char *start = basename((char*)path);
 		if (*start == '.')
-			return make_hidden(path);
+			return make_hidden(wpath);
 	}
 	return ret;
 }
 
-#undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
 	va_list args;
 	unsigned mode;
 	int fd;
+	wchar_t wfilename[MAX_PATH];
 
 	va_start(args, oflags);
 	mode = va_arg(args, int);
@@ -331,10 +335,12 @@ int mingw_open (const char *filename, int oflags, ...)
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
 
-	fd = open(filename, oflags, mode);
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	fd = _wopen(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
-		DWORD attrs = GetFileAttributes(filename);
+		DWORD attrs = GetFileAttributesW(wfilename);
 		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
 			errno = EISDIR;
 	}
@@ -346,7 +352,7 @@ int mingw_open (const char *filename, int oflags, ...)
 		 * such a file is created.
 		 */
 		const char *start = basename((char*)filename);
-		if (*start == '.' && make_hidden(filename))
+		if (*start == '.' && make_hidden(wfilename))
 			warning("Could not mark '%s' as hidden.", filename);
 	}
 	return fd;
@@ -369,38 +375,69 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 	return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
-#undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = fopen(filename, otype);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfopen(wfilename, wotype);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
-#undef freopen
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
 {
 	int hide = 0;
 	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (hide_dotfiles == HIDE_DOTFILES_TRUE &&
 	    basename((char*)filename)[0] == '.')
 		hide = access(filename, F_OK);
 	if (filename && !strcmp(filename, "/dev/null"))
 		filename = "nul";
-	file = freopen(filename, otype, stream);
-	if (file && hide && make_hidden(filename))
+	if (xutftowcs_path(wfilename, filename) < 0 ||
+		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && make_hidden(wfilename))
 		warning("Could not mark '%s' as hidden.", filename);
 	return file;
 }
 
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -426,10 +463,12 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
  */
 static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
-	int err;
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
-	if (!(err = get_file_attr(file_name, &fdata))) {
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
 		buf->st_ino = 0;
 		buf->st_gid = 0;
 		buf->st_uid = 0;
@@ -442,8 +481,8 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-			WIN32_FIND_DATAA findbuf;
-			HANDLE handle = FindFirstFileA(file_name, &findbuf);
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
 			if (handle != INVALID_HANDLE_VALUE) {
 				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
 						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
@@ -462,7 +501,23 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 		}
 		return 0;
 	}
-	errno = err;
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	default:
+		errno = ENOENT;
+		break;
+	}
 	return -1;
 }
 
@@ -551,16 +606,20 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
 {
 	FILETIME mft, aft;
 	int fh, rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
 
 	/* must have write permission */
-	DWORD attrs = GetFileAttributes(file_name);
+	attrs = GetFileAttributesW(wfilename);
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors here; open() will report them */
-		SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
 	}
 
-	if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+	if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
 		rc = -1;
 		goto revert_attrs;
 	}
@@ -583,7 +642,7 @@ revert_attrs:
 	if (attrs != INVALID_FILE_ATTRIBUTES &&
 	    (attrs & FILE_ATTRIBUTE_READONLY)) {
 		/* ignore errors again */
-		SetFileAttributes(file_name, attrs);
+		SetFileAttributesW(wfilename, attrs);
 	}
 	return rc;
 }
@@ -594,6 +653,18 @@ unsigned int sleep (unsigned int seconds)
 	return 0;
 }
 
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
 int mkstemp(char *template)
 {
 	char *filename = mktemp(template);
@@ -652,17 +723,18 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
 	return result;
 }
 
-#undef getcwd
 char *mingw_getcwd(char *pointer, int len)
 {
 	int i;
-	char *ret = getcwd(pointer, len);
-	if (!ret)
-		return ret;
+	wchar_t wpointer[MAX_PATH];
+	if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+		return NULL;
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
 	for (i = 0; pointer[i]; i++)
 		if (pointer[i] == '\\')
 			pointer[i] = '/';
-	return ret;
+	return pointer;
 }
 
 #undef getenv
@@ -1497,33 +1569,36 @@ int mingw_rename(const char *pold, const char *pnew)
 {
 	DWORD attrs, gle;
 	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+		return -1;
 
 	/*
 	 * Try native rename() first to get errno right.
 	 * It is based on MoveFile(), which cannot overwrite existing files.
 	 */
-	if (!rename(pold, pnew))
+	if (!_wrename(wpold, wpnew))
 		return 0;
 	if (errno != EEXIST)
 		return -1;
 repeat:
-	if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 		return 0;
 	/* TODO: translate more errors */
 	gle = GetLastError();
 	if (gle == ERROR_ACCESS_DENIED &&
-	    (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
 		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
 			errno = EISDIR;
 			return -1;
 		}
 		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
-		    SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
-			if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
 				return 0;
 			gle = GetLastError();
 			/* revert file attributes on failure */
-			SetFileAttributes(pnew, attrs);
+			SetFileAttributesW(wpnew, attrs);
 		}
 	}
 	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
@@ -1733,11 +1808,16 @@ void mingw_open_html(const char *unixpath)
 
 int link(const char *oldpath, const char *newpath)
 {
-	typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+	typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
 	static T create_hard_link = NULL;
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
 	if (!create_hard_link) {
 		create_hard_link = (T) GetProcAddress(
-			GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+			GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
 		if (!create_hard_link)
 			create_hard_link = (T)-1;
 	}
@@ -1745,7 +1825,7 @@ int link(const char *oldpath, const char *newpath)
 		errno = ENOSYS;
 		return -1;
 	}
-	if (!create_hard_link(newpath, oldpath, NULL)) {
+	if (!create_hard_link(wnewpath, woldpath, NULL)) {
 		errno = err_win_to_posix(GetLastError());
 		return -1;
 	}
diff --git a/compat/mingw.h b/compat/mingw.h
index 661455efb2..b06fb8917c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -182,6 +182,19 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 

From d9fd404b8d2a34ebe70ae7ad8e6c011693d91c84 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 22:01:09 +0100
Subject: [PATCH 3668/3720] Win32: Unicode file name support (dirent)

Changes opendir/readdir to use Windows Unicode APIs and convert between
UTF-8/UTF-16.

Removes parameter checks that are already covered by xutftowcs_path. This
changes detection of ENAMETOOLONG from MAX_PATH - 2 to MAX_PATH (matching
is_dir_empty in mingw.c). If name + "/*" or the resulting absolute path is
too long, FindFirstFile fails and errno is set through err_win_to_posix.

Increases the size of dirent.d_name to accommodate the full
WIN32_FIND_DATA.cFileName converted to UTF-8 (UTF-16 to UTF-8 conversion
may grow by factor three in the worst case).

Signed-off-by: Karsten Blees 
---
 compat/win32/dirent.c | 30 ++++++++++--------------------
 compat/win32/dirent.h |  2 +-
 2 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c
index 82a515c21b..52420ec7d4 100644
--- a/compat/win32/dirent.c
+++ b/compat/win32/dirent.c
@@ -6,10 +6,10 @@ struct DIR {
 	int dd_stat;          /* 0-based index */
 };
 
-static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
 {
-	/* copy file name from WIN32_FIND_DATA to dirent */
-	memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+	/* convert UTF-16 name to UTF-8 */
+	xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
 
 	/* Set file type, based on WIN32_FIND_DATA */
 	if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -20,25 +20,15 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
 
 DIR *opendir(const char *name)
 {
-	char pattern[MAX_PATH];
-	WIN32_FIND_DATAA fdata;
+	wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
+	WIN32_FIND_DATAW fdata;
 	HANDLE h;
 	int len;
 	DIR *dir;
 
-	/* check that name is not NULL */
-	if (!name) {
-		errno = EINVAL;
+	/* convert name to UTF-16 and check length < MAX_PATH */
+	if ((len = xutftowcs_path(pattern, name)) < 0)
 		return NULL;
-	}
-	/* check that the pattern won't be too long for FindFirstFileA */
-	len = strlen(name);
-	if (len + 2 >= MAX_PATH) {
-		errno = ENAMETOOLONG;
-		return NULL;
-	}
-	/* copy name to temp buffer */
-	memcpy(pattern, name, len + 1);
 
 	/* append optional '/' and wildcard '*' */
 	if (len && !is_dir_sep(pattern[len - 1]))
@@ -47,7 +37,7 @@ DIR *opendir(const char *name)
 	pattern[len] = 0;
 
 	/* open find handle */
-	h = FindFirstFileA(pattern, &fdata);
+	h = FindFirstFileW(pattern, &fdata);
 	if (h == INVALID_HANDLE_VALUE) {
 		DWORD err = GetLastError();
 		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
@@ -72,8 +62,8 @@ struct dirent *readdir(DIR *dir)
 	/* if first entry, dirent has already been set up by opendir */
 	if (dir->dd_stat) {
 		/* get next entry and convert from WIN32_FIND_DATA to dirent */
-		WIN32_FIND_DATAA fdata;
-		if (FindNextFileA(dir->dd_handle, &fdata)) {
+		WIN32_FIND_DATAW fdata;
+		if (FindNextFileW(dir->dd_handle, &fdata)) {
 			finddata2dirent(&dir->dd_dir, &fdata);
 		} else {
 			DWORD lasterr = GetLastError();
diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h
index 8838cd61fc..058207e4bf 100644
--- a/compat/win32/dirent.h
+++ b/compat/win32/dirent.h
@@ -10,7 +10,7 @@ typedef struct DIR DIR;
 
 struct dirent {
 	unsigned char d_type;      /* file type to prevent lstat after readdir */
-	char d_name[MAX_PATH];     /* file name */
+	char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
 };
 
 DIR *opendir(const char *dirname);

From 799bed21b2f518de1d2fffb5d0fd70dbcd8144b2 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 4 Feb 2012 21:54:36 +0100
Subject: [PATCH 3669/3720] Unicode file name support (gitk and git-gui)

Assumes file names in git tree objects are UTF-8 encoded.

On most unix systems, the system encoding (and thus the TCL system
encoding) will be UTF-8, so file names will be displayed correctly.

On Windows, it is impossible to set the system encoding to UTF-8. Changing
the TCL system encoding (via 'encoding system ...', e.g. in the startup
code) is explicitly discouraged by the TCL docs.

Change gitk and git-gui functions dealing with file names to always convert
from and to UTF-8.

Signed-off-by: Karsten Blees 
---
 git-gui/git-gui.sh      | 11 +++++++----
 git-gui/lib/browser.tcl |  2 +-
 git-gui/lib/index.tcl   |  6 +++---
 gitk-git/gitk           | 16 ++++++++--------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index a59020bcc5..e5038ddd12 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -533,6 +533,9 @@ proc git {args} {
 
 	_trace_exec [concat $opt $cmdp $args]
 	set result [eval exec $opt $cmdp $args]
+	if {[encoding system] != "utf-8"} {
+		set result [encoding convertfrom utf-8 [encoding convertto $result]]
+	}
 	if {$::_trace} {
 		puts stderr "< $result"
 	}
@@ -1087,7 +1090,7 @@ git-version proc _parse_config {arr_name args} {
 				[list git_read config] \
 				$args \
 				[list --null --list]]
-			fconfigure $fd_rc -translation binary
+			fconfigure $fd_rc -translation binary -encoding utf-8
 			set buf [read $fd_rc]
 			close $fd_rc
 		}
@@ -1652,7 +1655,7 @@ proc read_diff_index {fd after} {
 		set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			[lindex $i 4]? \
 			[list [lindex $i 0] [lindex $i 2]] \
 			[list]
@@ -1685,7 +1688,7 @@ proc read_diff_files {fd after} {
 		set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 		set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
 		merge_state \
-			[encoding convertfrom $p] \
+			[encoding convertfrom utf-8 $p] \
 			?[lindex $i 4] \
 			[list] \
 			[list [lindex $i 0] [lindex $i 2]]
@@ -1708,7 +1711,7 @@ proc read_ls_others {fd after} {
 	set pck [split $buf_rlo "\0"]
 	set buf_rlo [lindex $pck end]
 	foreach p [lrange $pck 0 end-1] {
-		set p [encoding convertfrom $p]
+		set p [encoding convertfrom utf-8 $p]
 		if {[string index $p end] eq {/}} {
 			set p [string range $p 0 end-1]
 		}
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 4fca8fb13c..555db896f4 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -197,7 +197,7 @@ method _ls {tree_id {name {}}} {
 	$w conf -state disabled
 
 	set fd [git_read ls-tree -z $tree_id]
-	fconfigure $fd -blocking 0 -translation binary
+	fconfigure $fd -blocking 0 -translation binary -encoding utf-8
 	fileevent $fd readable [cb _read $fd]
 }
 
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 8efbbdde21..6ca0a6e369 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -115,7 +115,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
 		set info [lindex $s 2]
 		if {$info eq {}} continue
 
-		puts -nonewline $fd "$info\t[encoding convertto $path]\0"
+		puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -186,7 +186,7 @@ proc write_update_index {fd pathList totalCnt batch after} {
 		?M {set new M_}
 		?? {continue}
 		}
-		puts -nonewline $fd "[encoding convertto $path]\0"
+		puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 		display_file $path $new
 	}
 
@@ -247,7 +247,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
 		?M -
 		?T -
 		?D {
-			puts -nonewline $fd "[encoding convertto $path]\0"
+			puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
 			display_file $path ?_
 		}
 		}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 16ff52a2c1..59693c0005 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7329,7 +7329,7 @@ proc gettreeline {gtf id} {
 	if {[string index $fname 0] eq "\""} {
 	    set fname [lindex $fname 0]
 	}
-	set fname [encoding convertfrom $fname]
+	set fname [encoding convertfrom utf-8 $fname]
 	lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -7551,7 +7551,7 @@ proc gettreediffline {gdtf ids} {
 	    if {[string index $file 0] eq "\""} {
 		set file [lindex $file 0]
 	    }
-	    set file [encoding convertfrom $file]
+	    set file [encoding convertfrom utf-8 $file]
 	    if {$file ne [lindex $treediff end]} {
 		lappend treediff $file
 		lappend sublist $file
@@ -7700,7 +7700,7 @@ proc makediffhdr {fname ids} {
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -7734,7 +7734,7 @@ proc getblobdiffline {bdf ids} {
 	}
 	if {![string compare -length 5 "diff " $line]} {
 	    if {![regexp {^diff (--cc|--git) } $line m type]} {
-		set line [encoding convertfrom $line]
+		set line [encoding convertfrom utf-8 $line]
 		$ctext insert end "$line\n" hunksep
 		continue
 	    }
@@ -7781,7 +7781,7 @@ proc getblobdiffline {bdf ids} {
 	    makediffhdr $fname $ids
 
 	} elseif {![string compare -length 16 "* Unmerged path " $line]} {
-	    set fname [encoding convertfrom [string range $line 16 end]]
+	    set fname [encoding convertfrom utf-8 [string range $line 16 end]]
 	    $ctext insert end "\n"
 	    set curdiffstart [$ctext index "end - 1c"]
 	    lappend ctext_file_names $fname
@@ -7836,7 +7836,7 @@ proc getblobdiffline {bdf ids} {
 		if {[string index $fname 0] eq "\""} {
 		    set fname [lindex $fname 0]
 		}
-		set fname [encoding convertfrom $fname]
+		set fname [encoding convertfrom utf-8 $fname]
 		set i [lsearch -exact $treediffs($ids) $fname]
 		if {$i >= 0} {
 		    setinlist difffilestart $i $curdiffstart
@@ -7855,7 +7855,7 @@ proc getblobdiffline {bdf ids} {
 		set diffinhdr 0
 		continue
 	    }
-	    set line [encoding convertfrom $line]
+	    set line [encoding convertfrom utf-8 $line]
 	    $ctext insert end "$line\n" filesep
 
 	} else {
@@ -11521,7 +11521,7 @@ proc cache_gitattr {attr pathlist} {
 	    foreach row [split $rlist "\n"] {
 		if {[regexp "(.*): $attr: (.*)" $row m path value]} {
 		    if {[string index $path 0] eq "\""} {
-			set path [encoding convertfrom [lindex $path 0]]
+			set path [encoding convertfrom utf-8 [lindex $path 0]]
 		    }
 		    set path_attr_cache($attr,$path) $value
 		}

From 25730abb5ce93fc1bd5a6c9a7eccf9b3ae2802b7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:27:53 +0100
Subject: [PATCH 3670/3720] Win32: Unicode arguments (outgoing)

Convert command line arguments from UTF-8 to UTF-16 when creating other
processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index d81e9c02c1..87b5e3bafa 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -955,9 +955,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFO si;
+	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
 	struct strbuf envblk, args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
 	unsigned flags;
 	BOOL ret;
 
@@ -993,6 +994,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	si.hStdOutput = winansi_get_osfhandle(fhout);
 	si.hStdError = winansi_get_osfhandle(fherr);
 
+	if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
 	/* concatenate argv, quoting args as we go */
 	strbuf_init(&args, 0);
 	if (prepend_cmd) {
@@ -1010,6 +1016,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 			free(quoted);
 	}
 
+	wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
@@ -1031,12 +1041,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	}
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir, &si, &pi);
+	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
 	if (env)
 		strbuf_release(&envblk);
-	strbuf_release(&args);
+	free(wargs);
 
 	if (!ret) {
 		errno = ENOENT;

From 92d755f3c5c343cd5853cf32e1e8ae326ebaee18 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 16 Jan 2011 18:28:27 +0100
Subject: [PATCH 3671/3720] Win32: Unicode arguments (incoming)

Convert command line arguments from UTF-16 to UTF-8 on startup.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 87b5e3bafa..ab5216feb8 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2042,10 +2042,41 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
  */
 int _CRT_glob = 0;
 
+typedef struct {
+	int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+		_startupinfo *si);
+
 void mingw_startup()
 {
-	/* copy executable name to argv[0] */
-	__argv[0] = xstrdup(_pgmptr);
+	int i, len, maxlen, argc;
+	char *buffer;
+	wchar_t **wenv, **wargv;
+	_startupinfo si;
+
+	/* get wide char arguments and environment */
+	si.newmode = 0;
+	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(_wpgmptr);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = xmalloc(maxlen);
+
+	/* convert command line arguments and environment to UTF-8 */
+	len = xwcstoutf(buffer, _wpgmptr, maxlen);
+	__argv[0] = xmemdupz(buffer, len);
+	for (i = 1; i < argc; i++) {
+		len = xwcstoutf(buffer, wargv[i], maxlen);
+		__argv[i] = xmemdupz(buffer, len);
+	}
+	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);

From 62b2423d3474688cd0d04a2d59a3f8c64ab8c03a Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:17:49 +0100
Subject: [PATCH 3672/3720] Win32: sync Unicode console output and file system

Use the same Unicode conversion functions for file names and console
conversions so that the file system and console output are in sync when
checking out legacy encoded repositories (i.e. with invalid UTF-8 file
names).

Signed-off-by: Karsten Blees 
---
 compat/winansi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/winansi.c b/compat/winansi.c
index a3e4d88295..9f95954390 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -120,8 +120,7 @@ static void write_console(unsigned char *str, size_t len)
 	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
 
 	/* convert utf-8 to utf-16 */
-	int wlen = MultiByteToWideChar(CP_UTF8, 0, (char*) str, len, wbuf,
-			ARRAY_SIZE(wbuf));
+	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, NULL, NULL);

From ed60de3934062d4291535d5de13e87bc3ad3daf6 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:07:46 +0100
Subject: [PATCH 3673/3720] Win32: Unicode environment (outgoing)

Convert environment from UTF-8 to UTF-16 when creating other processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index ab5216feb8..7e82b519ae 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -957,9 +957,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 {
 	STARTUPINFOW si;
 	PROCESS_INFORMATION pi;
-	struct strbuf envblk, args;
-	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
-	unsigned flags;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 
 	/* Determine whether or not we are associated to a console */
@@ -976,7 +976,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * instead of CREATE_NO_WINDOW to make ssh
 		 * recognize that it has no console.
 		 */
-		flags = DETACHED_PROCESS;
+		flags |= DETACHED_PROCESS;
 	} else {
 		/* There is already a console. If we specified
 		 * DETACHED_PROCESS here, too, Windows would
@@ -984,7 +984,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		 * The same is true for CREATE_NO_WINDOW.
 		 * Go figure!
 		 */
-		flags = 0;
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
@@ -1023,6 +1022,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	if (env) {
 		int count = 0;
 		char **e, **sorted_env;
+		int size = 0, wenvsz = 0, wenvpos = 0;
 
 		for (e = env; *e; e++)
 			count++;
@@ -1032,20 +1032,22 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
 		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
 
-		strbuf_init(&envblk, 0);
+		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
-			strbuf_addstr(&envblk, *e);
-			strbuf_addch(&envblk, '\0');
+			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
 		}
+		/* add final \0 terminator */
+		wenvblk[wenvpos] = 0;
 		free(sorted_env);
 	}
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-		env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
+		wenvblk, dir ? wdir : NULL, &si, &pi);
 
-	if (env)
-		strbuf_release(&envblk);
+	free(wenvblk);
 	free(wargs);
 
 	if (!ret) {

From 6dfb4571395ba1363030d126e9307add429e566c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 25 Apr 2011 23:32:27 +0100
Subject: [PATCH 3674/3720] Win32: Unicode environment (incoming)

Convert environment from UTF-16 to UTF-8 on startup.

No changes to getenv() are necessary, as the MSVCRT version is implemented
on top of char **environ.

However, putenv / _wputenv from MSVCRT no longer work, for two reasons:
1. they try to keep environ, _wenviron and the Win32 process environment
in sync, using the default system encoding instead of UTF-8 to convert
between charsets
2. msysgit and MSVCRT use different allocators, memory allocated in git
cannot be freed by the CRT and vice versa

Implement mingw_putenv using the env_setenv helper function from the
environment merge code.

Note that in case of memory allocation failure, putenv now dies with error
message (due to xrealloc) instead of failing with ENOMEM. As git assumes
setenv / putenv to always succeed, this prevents it from continuing with
incorrect settings.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 15 +++++++++++++++
 compat/mingw.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/compat/mingw.c b/compat/mingw.c
index 7e82b519ae..727e389025 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1284,6 +1284,12 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -2066,6 +2072,11 @@ void mingw_startup()
 	maxlen = wcslen(_wpgmptr);
 	for (i = 1; i < argc; i++)
 		maxlen = max(maxlen, wcslen(wargv[i]));
+	for (i = 0; wenv[i]; i++)
+		maxlen = max(maxlen, wcslen(wenv[i]));
+
+	/* nedmalloc can't free CRT memory, allocate resizable environment list */
+	environ = xcalloc(i + 1, sizeof(char*));
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2078,6 +2089,10 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wargv[i], maxlen);
 		__argv[i] = xmemdupz(buffer, len);
 	}
+	for (i = 0; wenv[i]; i++) {
+		len = xwcstoutf(buffer, wenv[i], maxlen);
+		environ[i] = xmemdupz(buffer, len);
+	}
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */
diff --git a/compat/mingw.h b/compat/mingw.h
index b06fb8917c..8980101ba1 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -200,6 +200,8 @@ char *mingw_getcwd(char *pointer, int len);
 
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
+int mingw_putenv(const char *namevalue);
+#define putenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 3d7ce6bba689a7b8b76c030644b6871943d8ef1c Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 20 Aug 2011 14:27:02 +0200
Subject: [PATCH 3675/3720] MinGW: disable legacy encoding tests

On Windows, all native APIs are Unicode-based. It is impossible to pass
legacy encoded byte arrays to a process via command line or environment
variables. Disable the tests that try to do so.

In t3901, most tests still work if we don't mess up the repository encoding
in setup, so don't switch to ISO-8859-1 on MinGW.

Note that i18n tests that do their encoding tricks via encoded files (such
as t3900) are not affected by this.

Signed-off-by: Karsten Blees 
---
 t/t3901-i18n-patch.sh | 19 +++++++++++--------
 t/t4201-shortlog.sh   |  6 +++---
 t/t8005-blame-i18n.sh |  8 ++++----
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 31a5770b34..55c8a2f576 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -54,10 +54,13 @@ test_expect_success setup '
 	git add yours &&
 	git commit -s -m "Second on side" &&
 
-	# the second one on the side branch is ISO-8859-1
-	git config i18n.commitencoding ISO8859-1 &&
-	# use author and committer name in ISO-8859-1 to match it.
-	. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+	if test_have_prereq NOT_MINGW
+	then
+		# the second one on the side branch is ISO-8859-1
+		git config i18n.commitencoding ISO8859-1 &&
+		# use author and committer name in ISO-8859-1 to match it.
+		. "$TEST_DIRECTORY"/t3901-8859-1.txt
+	fi &&
 	test_tick &&
 	echo Yet another >theirs &&
 	git add theirs &&
@@ -119,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
 	check_encoding 2
 '
 
-test_expect_success 'rebase (L/L)' '
+test_expect_success NOT_MINGW 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
 	git config i18n.commitencoding ISO8859-1 &&
 	git config i18n.logoutputencoding ISO8859-1 &&
@@ -131,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 	check_encoding 2 8859
 '
 
-test_expect_success 'rebase (L/U)' '
+test_expect_success NOT_MINGW 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
 	git config i18n.commitencoding ISO8859-1 &&
@@ -159,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/L)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
 	git config i18n.commitencoding ISO8859-1 &&
@@ -189,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	check_encoding 3
 '
 
-test_expect_success 'cherry-pick(L/U)' '
+test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6872ba1a42..48963811bf 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
 	test_cmp expect log.predictable
 '
 
-test_expect_success 'shortlog wrapping' '
+test_expect_success NOT_MINGW 'shortlog wrapping' '
 	cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
 	test_cmp expect out
 '
 
-test_expect_success 'shortlog from non-git directory' '
+test_expect_success NOT_MINGW 'shortlog from non-git directory' '
 	git log HEAD >log &&
 	GIT_DIR=non-existing git shortlog -w out &&
 	test_cmp expect out
@@ -135,7 +135,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success 'shortlog encoding' '
+test_expect_success NOT_MINGW 'shortlog encoding' '
 	git reset --hard "$commit" &&
 	git config --unset i18n.commitencoding &&
 	echo 2 > a1 &&
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index cb390559f9..a6e73d0635 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.commitencoding' '
 	git blame --incremental file | \
 		egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects i18n.logoutputencoding' '
 	git config i18n.logoutputencoding eucJP &&
 	git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=UTF-8' '
 	git blame --incremental --encoding=UTF-8 file | \
 		egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success \
+test_expect_success NOT_MINGW \
 	'blame respects --encoding=none' '
 	git blame --incremental --encoding=none file | \
 		egrep "^(author|summary) " > actual &&

From 2648b905ec0f97eb141bd078052d3275219e0f42 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:29:40 +0100
Subject: [PATCH 3676/3720] Win32: fix environment memory leaks

All functions that modify the environment have memory leaks.

Disable gitunsetenv in the Makefile and use env_setenv (via mingw_putenv)
instead (this frees removed environment entries).

Move xstrdup from env_setenv to make_augmented_environ, so that
mingw_putenv no longer copies the environment entries (according to POSIX
[1], "the string [...] shall become part of the environment"). This also
fixes the memory leak in gitsetenv, which expects a POSIX compliant putenv.

[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html

Note: This patch depends on taking control of char **environ and having
our own mingw_putenv (both introduced in "Win32: Unicode environment
(incoming)").

Signed-off-by: Karsten Blees 
---
 Makefile       |  2 --
 compat/mingw.c | 10 ++++++----
 compat/mingw.h |  1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 6f7382bade..53665cbc69 100644
--- a/Makefile
+++ b/Makefile
@@ -1211,7 +1211,6 @@ ifeq ($(uname_S),Windows)
 	NO_IPV6 = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
@@ -1306,7 +1305,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SYMLINK_HEAD = YesPlease
 	NO_UNIX_SOCKETS = YesPlease
 	NO_SETENV = YesPlease
-	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_STRTOK_R = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index 727e389025..3dfa95a473 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1257,14 +1257,14 @@ static char **env_setenv(char **env, const char *name)
 			for (i = 0; env[i]; i++)
 				;
 			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 			env[i+1] = NULL;
 		}
 	}
 	else {
 		free(env[i]);
 		if (*eq)
-			env[i] = xstrdup(name);
+			env[i] = (char*) name;
 		else
 			for (; env[i]; i++)
 				env[i] = env[i+1];
@@ -1279,8 +1279,10 @@ char **make_augmented_environ(const char *const *vars)
 {
 	char **env = copy_environ();
 
-	while (*vars)
-		env = env_setenv(env, *vars++);
+	while (*vars) {
+		const char *v = *vars++;
+		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+	}
 	return env;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index 8980101ba1..e6ce0bcb7a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -202,6 +202,7 @@ char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 int mingw_putenv(const char *namevalue);
 #define putenv mingw_putenv
+#define unsetenv mingw_putenv
 
 int mingw_gethostname(char *host, int namelen);
 #define gethostname mingw_gethostname

From 61da008f56f0c2fe331f8947d40d43b818bbc2c8 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sat, 14 Jan 2012 23:42:09 +0100
Subject: [PATCH 3677/3720] Win32: unify environment case-sensitivity

The environment on Windows is case-insensitive. Some environment functions
(such as unsetenv and make_augmented_environ) have always used case-
sensitive comparisons instead, while others (getenv, putenv, sorting in
spawn*) were case-insensitive.

Prevent potential inconsistencies by using case-insensitive comparison in
lookup_env (used by putenv, unsetenv and make_augmented_environ).

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 3dfa95a473..4e514e1924 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1236,8 +1236,7 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 	int i;
 
 	for (i = 0; env[i]; i++) {
-		if (0 == strncmp(env[i], name, nmln)
-		    && '=' == env[i][nmln])
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
 			/* matches */
 			return i;
 	}

From 6416ad38d5b631086e6c2c6783a0b76291f3dc83 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 25 Nov 2011 21:33:17 +0100
Subject: [PATCH 3678/3720] Win32: simplify internal mingw_spawn* APIs

The only public spawn function that needs to tweak the environment is
mingw_spawnvpe (called from start_command). Nevertheless, all internal
spawn* functions take an env parameter and needlessly pass the global
char **environ around. Remove the env parameter where it's not needed.

This removes the internal mingw_execve abstraction, which is no longer
needed.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 4e514e1924..dcfe4969d3 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1077,10 +1077,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-			   int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -1122,7 +1121,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 	return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
 	const char *interpr = parse_interpreter(cmd);
 	char **path;
@@ -1140,7 +1139,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 		argv2 = xmalloc(sizeof(*argv) * (argc+1));
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-		pid = mingw_spawnve(prog, argv2, env, 1);
+		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -1155,13 +1154,13 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
 	return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+void mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
-	if (!try_shell_exec(cmd, argv, (char **)env)) {
+	if (!try_shell_exec(cmd, argv)) {
 		int pid, status;
 
-		pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
 			return;
 		if (waitpid(pid, &status, 0) < 0)
@@ -1176,7 +1175,7 @@ int mingw_execvp(const char *cmd, char *const *argv)
 	char *prog = path_lookup(cmd, path, 0);
 
 	if (prog) {
-		mingw_execve(prog, argv, environ);
+		mingw_execv(prog, argv);
 		free(prog);
 	} else
 		errno = ENOENT;
@@ -1185,12 +1184,6 @@ int mingw_execvp(const char *cmd, char *const *argv)
 	return -1;
 }
 
-int mingw_execv(const char *cmd, char *const *argv)
-{
-	mingw_execve(cmd, argv, environ);
-	return -1;
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
 	if (pid > 0 && sig == SIGTERM) {

From b0e829d93ea7a14aaa08247d5dd36b38640c6d53 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:05:04 +0100
Subject: [PATCH 3679/3720] Win32: move environment functions

Move environment helper functions up so that they can be reused by
mingw_getenv and mingw_spawnve_fd in subsequent patches.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 106 ++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index dcfe4969d3..bb0f3f5bed 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,6 +737,53 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
+static int env_compare(const void *a, const void *b)
+{
+	char *const *ea = a;
+	char *const *eb = b;
+	return strcasecmp(*ea, *eb);
+}
+
+static int lookup_env(char **env, const char *name, size_t nmln)
+{
+	int i;
+
+	for (i = 0; env[i]; i++) {
+		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
+			/* matches */
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * If name contains '=', then sets the variable, otherwise it unsets it
+ */
+static char **env_setenv(char **env, const char *name)
+{
+	char *eq = strchrnul(name, '=');
+	int i = lookup_env(env, name, eq-name);
+
+	if (i < 0) {
+		if (*eq) {
+			for (i = 0; env[i]; i++)
+				;
+			env = xrealloc(env, (i+2)*sizeof(*env));
+			env[i] = (char*) name;
+			env[i+1] = NULL;
+		}
+	}
+	else {
+		free(env[i]);
+		if (*eq)
+			env[i] = (char*) name;
+		else
+			for (; env[i]; i++)
+				env[i] = env[i+1];
+	}
+	return env;
+}
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -754,6 +801,12 @@ char *mingw_getenv(const char *name)
 	return result;
 }
 
+int mingw_putenv(const char *namevalue)
+{
+	environ = env_setenv(environ, namevalue);
+	return 0;
+}
+
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -936,13 +989,6 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
-static int env_compare(const void *a, const void *b)
-{
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
-}
-
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1224,46 +1270,6 @@ void free_environ(char **env)
 	free(env);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
-{
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
-	}
-	return -1;
-}
-
-/*
- * If name contains '=', then sets the variable, otherwise it unsets it
- */
-static char **env_setenv(char **env, const char *name)
-{
-	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
-
-	if (i < 0) {
-		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
-		}
-	}
-	else {
-		free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-	}
-	return env;
-}
-
 /*
  * Copies global environ and adjusts variables as specified by vars.
  */
@@ -1278,12 +1284,6 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-int mingw_putenv(const char *namevalue)
-{
-	environ = env_setenv(environ, namevalue);
-	return 0;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It

From 34a127b398b561970ebd3349088b5dd4ab9d6e7d Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Wed, 5 Oct 2011 22:01:46 +0200
Subject: [PATCH 3680/3720] Win32: unify environment function names

Environment helper functions use random naming ('env' prefix or suffix or
both, with or without '_'). Change to POSIX naming scheme ('env' suffix,
no '_').

Env_setenv has more in common with putenv than setenv. Change to do_putenv.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index bb0f3f5bed..ceeca910d8 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,14 +737,14 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int env_compare(const void *a, const void *b)
+static int compareenv(const void *a, const void *b)
 {
 	char *const *ea = a;
 	char *const *eb = b;
 	return strcasecmp(*ea, *eb);
 }
 
-static int lookup_env(char **env, const char *name, size_t nmln)
+static int lookupenv(char **env, const char *name, size_t nmln)
 {
 	int i;
 
@@ -759,10 +759,10 @@ static int lookup_env(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **env_setenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name)
 {
 	char *eq = strchrnul(name, '=');
-	int i = lookup_env(env, name, eq-name);
+	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
@@ -803,7 +803,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = env_setenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue);
 	return 0;
 }
 
@@ -1076,7 +1076,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 		/* environment must be sorted */
 		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
 		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
 
 		/* create environment block from temporary environment */
 		for (e = sorted_env; *e; e++) {
@@ -1279,7 +1279,7 @@ char **make_augmented_environ(const char *const *vars)
 
 	while (*vars) {
 		const char *v = *vars++;
-		env = env_setenv(env, strchr(v, '=') ? xstrdup(v) : v);
+		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
 	}
 	return env;
 }

From b648168756ffecda156519e7d0a10191d45c6b51 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:31:57 +0100
Subject: [PATCH 3681/3720] Win32: factor out environment block creation

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 55 +++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index ceeca910d8..4d24ca06b6 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -989,6 +989,36 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 	return prog;
 }
 
+/*
+ * Create environment block suitable for CreateProcess.
+ */
+static wchar_t *make_environment_block(char **env)
+{
+	wchar_t *wenvblk = NULL;
+	int count = 0;
+	char **e, **tmpenv;
+	int size = 0, wenvsz = 0, wenvpos = 0;
+
+	for (e = env; *e; e++)
+		count++;
+
+	/* environment must be sorted */
+	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+
+	/* create environment block from temporary environment */
+	for (e = tmpenv; *e; e++) {
+		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
+		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+	}
+	/* add final \0 terminator */
+	wenvblk[wenvpos] = 0;
+	free(tmpenv);
+	return wenvblk;
+}
+
 struct pinfo_t {
 	struct pinfo_t *next;
 	pid_t pid;
@@ -1065,29 +1095,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env) {
-		int count = 0;
-		char **e, **sorted_env;
-		int size = 0, wenvsz = 0, wenvpos = 0;
-
-		for (e = env; *e; e++)
-			count++;
-
-		/* environment must be sorted */
-		sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
-		memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
-		qsort(sorted_env, count, sizeof(*sorted_env), compareenv);
-
-		/* create environment block from temporary environment */
-		for (e = sorted_env; *e; e++) {
-			size = 2 * strlen(*e) + 2; /* +2 for final \0 */
-			ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-			wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
-		}
-		/* add final \0 terminator */
-		wenvblk[wenvpos] = 0;
-		free(sorted_env);
-	}
+	if (env)
+		wenvblk = make_environment_block(env);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,

From 6fd39ad7c885d6b7999c07dbb3ca61d8af562577 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 00:57:14 +0100
Subject: [PATCH 3682/3720] Win32: don't copy the environment twice when
 spawning child processes

When spawning child processes via start_command(), the environment and all
environment entries are copied twice. First by make_augmented_environ /
copy_environ to merge with child_process.env. Then a second time by
make_environment_block to create a sorted environment block string as
required by CreateProcess.

Move the merge logic to make_environment_block so that we only need to copy
the environment once. This changes semantics of the env parameter: it now
expects a delta (such as child_process.env) rather than a full environment.
This is not a problem as the parameter is only used by start_command()
(all other callers previously passed char **environ, and now pass NULL).

The merge logic no longer xstrdup()s the environment strings, so do_putenv
must not free them. Add a parameter to distinguish this from normal putenv.

Remove the now unused make_augmented_environ / free_environ API.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 74 ++++++++++++++++----------------------------------
 compat/mingw.h |  6 ----
 run-command.c  | 10 ++-----
 3 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 4d24ca06b6..9ed3f82d33 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -759,7 +759,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
  */
-static char **do_putenv(char **env, const char *name)
+static char **do_putenv(char **env, const char *name, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
@@ -774,7 +774,8 @@ static char **do_putenv(char **env, const char *name)
 		}
 	}
 	else {
-		free(env[i]);
+		if (free_old)
+			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
 		else
@@ -803,7 +804,7 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue);
+	environ = do_putenv(environ, namevalue, 1);
 	return 0;
 }
 
@@ -990,21 +991,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 }
 
 /*
- * Create environment block suitable for CreateProcess.
+ * Create environment block suitable for CreateProcess. Merges current
+ * process environment and the supplied environment changes.
  */
-static wchar_t *make_environment_block(char **env)
+static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
 	int count = 0;
 	char **e, **tmpenv;
 	int size = 0, wenvsz = 0, wenvpos = 0;
 
-	for (e = env; *e; e++)
+	while (environ[count])
 		count++;
 
-	/* environment must be sorted */
+	/* copy the environment */
 	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
+	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+
+	/* merge supplied environment changes into the temporary environment */
+	for (e = deltaenv; e && *e; e++)
+		tmpenv = do_putenv(tmpenv, *e, 0);
+
+	/* environment must be sorted */
+	for (count = 0; tmpenv[count]; )
+		count++;
 	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
 
 	/* create environment block from temporary environment */
@@ -1027,7 +1037,7 @@ struct pinfo_t {
 struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
-static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
@@ -1095,8 +1105,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 	xutftowcs(wargs, args.buf, 2 * args.len + 1);
 	strbuf_release(&args);
 
-	if (env)
-		wenvblk = make_environment_block(env);
+	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
 	ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1134,10 +1143,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
 static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-	return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 		     const char *dir,
 		     int fhin, int fhout, int fherr)
 {
@@ -1161,14 +1170,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 				pid = -1;
 			}
 			else {
-				pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
 						       fhin, fhout, fherr);
 				free(iprog);
 			}
 			argv[0] = argv0;
 		}
 		else
-			pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
 					       fhin, fhout, fherr);
 		free(prog);
 	}
@@ -1258,41 +1267,6 @@ int mingw_kill(pid_t pid, int sig)
 	return -1;
 }
 
-static char **copy_environ(void)
-{
-	char **env;
-	int i = 0;
-	while (environ[i])
-		i++;
-	env = xmalloc((i+1)*sizeof(*env));
-	for (i = 0; environ[i]; i++)
-		env[i] = xstrdup(environ[i]);
-	env[i] = NULL;
-	return env;
-}
-
-void free_environ(char **env)
-{
-	int i;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-/*
- * Copies global environ and adjusts variables as specified by vars.
- */
-char **make_augmented_environ(const char *const *vars)
-{
-	char **env = copy_environ();
-
-	while (*vars) {
-		const char *v = *vars++;
-		env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
-	}
-	return env;
-}
-
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
diff --git a/compat/mingw.h b/compat/mingw.h
index e6ce0bcb7a..55cef8c73c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -335,12 +335,6 @@ void mingw_open_html(const char *path);
 void mingw_mark_as_git_dir(const char *dir);
 #define mark_as_git_dir mingw_mark_as_git_dir
 
-/*
- * helpers
- */
-
-char **make_augmented_environ(const char *const *vars);
-void free_environ(char **env);
 
 /**
  * Converts UTF-8 encoded string to UTF-16LE.
diff --git a/run-command.c b/run-command.c
index 606791dc67..e665368469 100644
--- a/run-command.c
+++ b/run-command.c
@@ -451,7 +451,6 @@ fail_pipe:
 {
 	int fhin = 0, fhout = 1, fherr = 2;
 	const char **sargv = cmd->argv;
-	char **env = environ;
 
 	if (cmd->no_stdin)
 		fhin = open("/dev/null", O_RDWR);
@@ -476,25 +475,20 @@ fail_pipe:
 	else if (cmd->out > 1)
 		fhout = dup(cmd->out);
 
-	if (cmd->env)
-		env = make_augmented_environ(cmd->env);
-
 	if (cmd->git_cmd) {
 		cmd->argv = prepare_git_cmd(cmd->argv);
 	} else if (cmd->use_shell) {
 		cmd->argv = prepare_shell_cmd(cmd->argv);
 	}
 
-	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
-				  fhin, fhout, fherr);
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
 	failed_errno = errno;
 	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 		error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 	if (cmd->clean_on_exit && cmd->pid >= 0)
 		mark_child_for_cleanup(cmd->pid);
 
-	if (cmd->env)
-		free_environ(env);
 	if (cmd->git_cmd)
 		free(cmd->argv);
 

From b2e6cddf49f32ea64dec47b34ec33a435e85f685 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Mon, 16 Jan 2012 00:00:35 +0100
Subject: [PATCH 3683/3720] Win32: reduce environment array reallocations

Move environment array reallocation from do_putenv to the respective
callers. Keep track of the environment size in a global variable. Use
ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a
sufficiently sized environment array in make_environment_block to prevent
reallocations.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 60 ++++++++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9ed3f82d33..dcd5c4139b 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -758,19 +758,19 @@ static int lookupenv(char **env, const char *name, size_t nmln)
 
 /*
  * If name contains '=', then sets the variable, otherwise it unsets it
+ * Size includes the terminating NULL. Env must have room for size + 1 entries
+ * (in case of insert). Returns the new size. Optionally frees removed entries.
  */
-static char **do_putenv(char **env, const char *name, int free_old)
+static int do_putenv(char **env, const char *name, int size, int free_old)
 {
 	char *eq = strchrnul(name, '=');
 	int i = lookupenv(env, name, eq-name);
 
 	if (i < 0) {
 		if (*eq) {
-			for (i = 0; env[i]; i++)
-				;
-			env = xrealloc(env, (i+2)*sizeof(*env));
-			env[i] = (char*) name;
-			env[i+1] = NULL;
+			env[size - 1] = (char*) name;
+			env[size] = NULL;
+			size++;
 		}
 	}
 	else {
@@ -778,13 +778,20 @@ static char **do_putenv(char **env, const char *name, int free_old)
 			free(env[i]);
 		if (*eq)
 			env[i] = (char*) name;
-		else
+		else {
 			for (; env[i]; i++)
 				env[i] = env[i+1];
+			size--;
+		}
 	}
-	return env;
+	return size;
 }
 
+/* used number of elements of environ array, including terminating NULL */
+static int environ_size = 0;
+/* allocated size of environ array, in bytes */
+static int environ_alloc = 0;
+
 #undef getenv
 char *mingw_getenv(const char *name)
 {
@@ -804,7 +811,8 @@ char *mingw_getenv(const char *name)
 
 int mingw_putenv(const char *namevalue)
 {
-	environ = do_putenv(environ, namevalue, 1);
+	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
+	environ_size = do_putenv(environ, namevalue, environ_size, 1);
 	return 0;
 }
 
@@ -997,31 +1005,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
 static wchar_t *make_environment_block(char **deltaenv)
 {
 	wchar_t *wenvblk = NULL;
-	int count = 0;
-	char **e, **tmpenv;
-	int size = 0, wenvsz = 0, wenvpos = 0;
+	char **tmpenv;
+	int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
 
-	while (environ[count])
-		count++;
+	while (deltaenv && deltaenv[i])
+		i++;
 
-	/* copy the environment */
-	tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
-	memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
+	/* copy the environment, leaving space for changes */
+	tmpenv = xmalloc((size + i) * sizeof(char*));
+	memcpy(tmpenv, environ, size * sizeof(char*));
 
 	/* merge supplied environment changes into the temporary environment */
-	for (e = deltaenv; e && *e; e++)
-		tmpenv = do_putenv(tmpenv, *e, 0);
+	for (i = 0; deltaenv && deltaenv[i]; i++)
+		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
 	/* environment must be sorted */
-	for (count = 0; tmpenv[count]; )
-		count++;
-	qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
+	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
 
 	/* create environment block from temporary environment */
-	for (e = tmpenv; *e; e++) {
-		size = 2 * strlen(*e) + 2; /* +2 for final \0 */
+	for (i = 0; tmpenv[i]; i++) {
+		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
 		ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-		wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
+		wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
 	}
 	/* add final \0 terminator */
 	wenvblk[wenvpos] = 0;
@@ -2053,7 +2058,9 @@ void mingw_startup()
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
 	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = xcalloc(i + 1, sizeof(char*));
+	environ = NULL;
+	environ_size = i + 1;
+	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
@@ -2070,6 +2077,7 @@ void mingw_startup()
 		len = xwcstoutf(buffer, wenv[i], maxlen);
 		environ[i] = xmemdupz(buffer, len);
 	}
+	environ[i] = NULL;
 	free(buffer);
 
 	/* initialize critical section for waitpid pinfo_t list */

From faa87aae2836427b2a9fa4ea725442db24446303 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:29:04 +0100
Subject: [PATCH 3684/3720] Win32: use low-level memory allocation during
 initialization

As of d41489a6 "Add more large blob test cases", git's high-level memory
allocation functions (xmalloc, xmemdupz etc.) access the environment to
simulate limited memory in tests (see 'getenv("GIT_ALLOC_LIMIT")' in
memory_limit_check()). These functions should not be used before the
environment is fully initialized (particularly not to initialize the
environment itself).

The current solution ('environ = NULL; ALLOC_GROW(environ...)') only works
because MSVCRT's getenv() reinitializes environ when it is NULL (i.e. it
leaves us with two sets of unusabe (non-UTF-8) and unfreeable (CRT-
allocated) environments).

Add our own set of malloc-or-die functions to be used in startup code.

Also check the result of __wgetmainargs, which may fail if there's not
enough memory for wide-char arguments and environment.

This patch is in preparation of the sorted environment feature, which
completely replaces MSVCRT's getenv() implementation.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 52 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index dcd5c4139b..ad5f87527f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2039,16 +2039,37 @@ typedef struct {
 extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
 		_startupinfo *si);
 
+static NORETURN void die_startup()
+{
+	fputs("fatal: not enough memory for initialization", stderr);
+	exit(128);
+}
+
+static void *malloc_startup(size_t size)
+{
+	void *result = malloc(size);
+	if (!result)
+		die_startup();
+	return result;
+}
+
+static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
+{
+	len = xwcstoutf(buffer, wcs, len) + 1;
+	return memcpy(malloc_startup(len), buffer, len);
+}
+
 void mingw_startup()
 {
-	int i, len, maxlen, argc;
+	int i, maxlen, argc;
 	char *buffer;
 	wchar_t **wenv, **wargv;
 	_startupinfo si;
 
 	/* get wide char arguments and environment */
 	si.newmode = 0;
-	__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si);
+	if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
+		die_startup();
 
 	/* determine size of argv and environ conversion buffer */
 	maxlen = wcslen(_wpgmptr);
@@ -2057,26 +2078,25 @@ void mingw_startup()
 	for (i = 0; wenv[i]; i++)
 		maxlen = max(maxlen, wcslen(wenv[i]));
 
-	/* nedmalloc can't free CRT memory, allocate resizable environment list */
-	environ = NULL;
+	/*
+	 * nedmalloc can't free CRT memory, allocate resizable environment
+	 * list. Note that xmalloc / xmemdupz etc. call getenv, so we cannot
+	 * use it while initializing the environment itself.
+	 */
 	environ_size = i + 1;
-	ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
+	environ_alloc = alloc_nr(environ_size * sizeof(char*));
+	environ = malloc_startup(environ_alloc);
 
 	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
 	maxlen = 3 * maxlen + 1;
-	buffer = xmalloc(maxlen);
+	buffer = malloc_startup(maxlen);
 
 	/* convert command line arguments and environment to UTF-8 */
-	len = xwcstoutf(buffer, _wpgmptr, maxlen);
-	__argv[0] = xmemdupz(buffer, len);
-	for (i = 1; i < argc; i++) {
-		len = xwcstoutf(buffer, wargv[i], maxlen);
-		__argv[i] = xmemdupz(buffer, len);
-	}
-	for (i = 0; wenv[i]; i++) {
-		len = xwcstoutf(buffer, wenv[i], maxlen);
-		environ[i] = xmemdupz(buffer, len);
-	}
+	__argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
+	for (i = 1; i < argc; i++)
+		__argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+	for (i = 0; wenv[i]; i++)
+		environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen);
 	environ[i] = NULL;
 	free(buffer);
 

From 6f74416223e0084dcc1da6403121dc98c7a8fbc1 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:30:02 +0100
Subject: [PATCH 3685/3720] Win32: keep the environment sorted

The Windows environment is sorted, keep it that way for O(log n)
environment access.

Change compareenv to compare only the keys, so that it can be used to
find an entry irrespective of the value.

Change lookupenv to binary seach for an entry. Return one's complement of
the insert position if not found (libc's bsearch returns NULL).

Replace MSVCRT's getenv with a minimal do_getenv based on the binary search
function.

Change do_putenv to insert new entries at the correct position. Simplify
the function by swapping if conditions and using memmove instead of for
loops.

Move qsort from make_environment_block to mingw_startup. We still need to
sort on startup to make sure that the environment is sorted according to
our compareenv function (while Win32 / CreateProcess requires the
environment block to be sorted case-insensitively, CreateProcess currently
doesn't enforce this, and some applications such as bash just don't care).

Note that environment functions are _not_ thread-safe and are not required
to be so by POSIX, the application is responsible for synchronizing access
to the environment. MSVCRT's getenv and our new getenv implementation are
better than that in that they are thread-safe with respect to other getenv
calls as long as the environment is not modified. Git's indiscriminate use
of getenv in background threads currently requires this property.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 98 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 62 insertions(+), 36 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index ad5f87527f..9afba8d4f8 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -737,23 +737,42 @@ char *mingw_getcwd(char *pointer, int len)
 	return pointer;
 }
 
-static int compareenv(const void *a, const void *b)
+/*
+ * Compare environment entries by key (i.e. stopping at '=' or '\0').
+ */
+static int compareenv(const void *v1, const void *v2)
 {
-	char *const *ea = a;
-	char *const *eb = b;
-	return strcasecmp(*ea, *eb);
+	const char *e1 = *(const char**)v1;
+	const char *e2 = *(const char**)v2;
+
+	for (;;) {
+		int c1 = *e1++;
+		int c2 = *e2++;
+		c1 = (c1 == '=') ? 0 : tolower(c1);
+		c2 = (c2 == '=') ? 0 : tolower(c2);
+		if (c1 > c2)
+			return 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 == 0)
+			return 0;
+	}
 }
 
-static int lookupenv(char **env, const char *name, size_t nmln)
+static int bsearchenv(char **env, const char *name, size_t size)
 {
-	int i;
-
-	for (i = 0; env[i]; i++) {
-		if (!strncasecmp(env[i], name, nmln) && '=' == env[i][nmln])
-			/* matches */
-			return i;
+	unsigned low = 0, high = size;
+	while (low < high) {
+		unsigned mid = low + ((high - low) >> 1);
+		int cmp = compareenv(&env[mid], &name);
+		if (cmp < 0)
+			low = mid + 1;
+		else if (cmp > 0)
+			high = mid;
+		else
+			return mid;
 	}
-	return -1;
+	return ~low; /* not found, return 1's complement of insert position */
 }
 
 /*
@@ -763,26 +782,24 @@ static int lookupenv(char **env, const char *name, size_t nmln)
  */
 static int do_putenv(char **env, const char *name, int size, int free_old)
 {
-	char *eq = strchrnul(name, '=');
-	int i = lookupenv(env, name, eq-name);
+	int i = bsearchenv(env, name, size - 1);
 
-	if (i < 0) {
-		if (*eq) {
-			env[size - 1] = (char*) name;
-			env[size] = NULL;
+	/* optionally free removed / replaced entry */
+	if (i >= 0 && free_old)
+		free(env[i]);
+
+	if (strchr(name, '=')) {
+		/* if new value ('key=value') is specified, insert or replace entry */
+		if (i < 0) {
+			i = ~i;
+			memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
 			size++;
 		}
-	}
-	else {
-		if (free_old)
-			free(env[i]);
-		if (*eq)
-			env[i] = (char*) name;
-		else {
-			for (; env[i]; i++)
-				env[i] = env[i+1];
-			size--;
-		}
+		env[i] = (char*) name;
+	} else if (i >= 0) {
+		/* otherwise ('key') remove existing entry */
+		size--;
+		memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
 	}
 	return size;
 }
@@ -792,15 +809,24 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-#undef getenv
+static char *do_getenv(const char *name)
+{
+	char *value;
+	int pos = bsearchenv(environ, name, environ_size - 1);
+	if (pos < 0)
+		return NULL;
+	value = strchr(environ[pos], '=');
+	return value ? &value[1] : NULL;
+}
+
 char *mingw_getenv(const char *name)
 {
-	char *result = getenv(name);
+	char *result = do_getenv(name);
 	if (!result && !strcmp(name, "TMPDIR")) {
 		/* on Windows it is TMP and TEMP */
-		result = getenv("TMP");
+		result = do_getenv("TMP");
 		if (!result)
-			result = getenv("TEMP");
+			result = do_getenv("TEMP");
 	}
 	else if (!result && !strcmp(name, "TERM")) {
 		/* simulate TERM to enable auto-color (see color.c) */
@@ -1019,9 +1045,6 @@ static wchar_t *make_environment_block(char **deltaenv)
 	for (i = 0; deltaenv && deltaenv[i]; i++)
 		size = do_putenv(tmpenv, deltaenv[i], size, 0);
 
-	/* environment must be sorted */
-	qsort(tmpenv, size - 1, sizeof(char*), compareenv);
-
 	/* create environment block from temporary environment */
 	for (i = 0; tmpenv[i]; i++) {
 		size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
@@ -2100,6 +2123,9 @@ void mingw_startup()
 	environ[i] = NULL;
 	free(buffer);
 
+	/* sort environment for O(log n) getenv / putenv */
+	qsort(environ, i, sizeof(char*), compareenv);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 4b443977d013842d922dafbf97d3727b718ffb73 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Sun, 15 Jan 2012 02:35:26 +0100
Subject: [PATCH 3686/3720] Win32: patch Windows environment on startup

Fix Windows specific environment settings on startup rather than checking
for special values on every getenv call.

As a side effect, this makes the patched environment (i.e. with properly
initialized TMPDIR and TERM) available to child processes.

Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 9afba8d4f8..d0ae52c2b4 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -809,7 +809,7 @@ static int environ_size = 0;
 /* allocated size of environ array, in bytes */
 static int environ_alloc = 0;
 
-static char *do_getenv(const char *name)
+char *mingw_getenv(const char *name)
 {
 	char *value;
 	int pos = bsearchenv(environ, name, environ_size - 1);
@@ -819,22 +819,6 @@ static char *do_getenv(const char *name)
 	return value ? &value[1] : NULL;
 }
 
-char *mingw_getenv(const char *name)
-{
-	char *result = do_getenv(name);
-	if (!result && !strcmp(name, "TMPDIR")) {
-		/* on Windows it is TMP and TEMP */
-		result = do_getenv("TMP");
-		if (!result)
-			result = do_getenv("TEMP");
-	}
-	else if (!result && !strcmp(name, "TERM")) {
-		/* simulate TERM to enable auto-color (see color.c) */
-		result = "winansi";
-	}
-	return result;
-}
-
 int mingw_putenv(const char *namevalue)
 {
 	ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
@@ -2126,6 +2110,21 @@ void mingw_startup()
 	/* sort environment for O(log n) getenv / putenv */
 	qsort(environ, i, sizeof(char*), compareenv);
 
+	/* fix Windows specific environment settings */
+
+	/* on Windows it is TMP and TEMP */
+	if (!getenv("TMPDIR")) {
+		const char *tmp = getenv("TMP");
+		if (!tmp)
+			tmp = getenv("TEMP");
+		if (tmp)
+			setenv("TMPDIR", tmp, 1);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "winansi", 1);
+
 	/* initialize critical section for waitpid pinfo_t list */
 	InitializeCriticalSection(&pinfo_cs);
 

From 71178fe7e8180cb98faed345dfa7437701e89ec7 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 15 Mar 2012 20:37:26 +0100
Subject: [PATCH 3687/3720] Win32: fix detection of empty directories in
 is_dir_empty

On Windows XP (not Win7), directories cannot be deleted while a find handle
is open, causing "Deletion of directory '...' failed. Should I try again?"
prompts.

Prior to 19d1e75d "Win32: Unicode file name support (except dirent)",
these failures were silently ignored due to strbuf_free in is_dir_empty
resetting GetLastError to ERROR_SUCCESS.

Close the find handle in is_dir_empty so that git doesn't block deletion
of the directory even after all other applications have released it.

Reported-by: John Chen 
Signed-off-by: Karsten Blees 
---
 compat/mingw.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index d0ae52c2b4..86c3fe7bdc 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -243,8 +243,11 @@ static int is_dir_empty(const wchar_t *wpath)
 
 	while (!wcscmp(findbuf.cFileName, L".") ||
 			!wcscmp(findbuf.cFileName, L".."))
-		if (!FindNextFileW(handle, &findbuf))
-			return GetLastError() == ERROR_NO_MORE_FILES;
+		if (!FindNextFileW(handle, &findbuf)) {
+			DWORD err = GetLastError();
+			FindClose(handle);
+			return err == ERROR_NO_MORE_FILES;
+		}
 	FindClose(handle);
 	return 0;
 }

From 1b12cb06ffd8a73a3d42f5df7fb7e76e1f868361 Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Thu, 1 Mar 2012 21:53:54 +0100
Subject: [PATCH 3688/3720] Win32: fix broken pipe detection

As of "Win32: Thread-safe windows console output", git-log no longer
terminates when the pager process dies. This is due to disabling buffering
for the replaced stdout / stderr streams. Git-log will periodically fflush
stdout (see write_or_die.c/mayble_flush_or_die()), but with no buffering,
this is a NOP that always succeeds (so we never detect the EPIPE error).

Exchange the original console handles with our console thread pipe handles
by accessing the internal MSVCRT data structures directly (which are
exposed via __pioinfo for some reason).

Implement this with minimal assumptions about the actual data structure to
make it work with different (hopefully even future) MSVCRT versions.

While messing with internal data structures is ugly, this patch solves the
problem at the source instead of adding more workarounds. We no longer need
the special winansi_isatty override, and the limitations documented in
"Win32: Thread-safe windows console output" are gone (i.e. fdopen(1/2)
returns unbuffered streams now, and isatty() for duped console file
descriptors works as expected).

Signed-off-by: Karsten Blees 
---
 compat/mingw.h   |   2 -
 compat/winansi.c | 112 +++++++++++++++++++++++++++++------------------
 2 files changed, 69 insertions(+), 45 deletions(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 55cef8c73c..18bf5fd2ce 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -305,9 +305,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
  */
 
 void winansi_init(void);
-int winansi_isatty(int fd);
 HANDLE winansi_get_osfhandle(int fd);
-#define isatty winansi_isatty
 
 /*
  * git specific compatibility
diff --git a/compat/winansi.c b/compat/winansi.c
index 9f95954390..040ef5adca 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -7,11 +7,6 @@
 #include 
 #include 
 
-/*
- Functions to be wrapped:
-*/
-#undef isatty
-
 /*
  ANSI codes used by git: m, K
 
@@ -103,6 +98,7 @@ static int is_console(int fd)
 
 	/* initialize attributes */
 	if (!initialized) {
+		console = hcon;
 		attr = plain_attr = sbi.wAttributes;
 		negative = 0;
 		initialized = 1;
@@ -463,29 +459,80 @@ static HANDLE duplicate_handle(HANDLE hnd)
 	return hresult;
 }
 
-static HANDLE redirect_console(FILE *stream, HANDLE *phcon, int new_fd)
+
+/*
+ * Make MSVCRT's internal file descriptor control structure accessible
+ * so that we can tweak OS handles and flags directly (we need MSVCRT
+ * to treat our pipe handle as if it were a console).
+ *
+ * We assume that the ioinfo structure (exposed by MSVCRT.dll via
+ * __pioinfo) starts with the OS handle and the flags. The exact size
+ * varies between MSVCRT versions, so we try different sizes until
+ * toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
+ * isatty(1).
+ */
+typedef struct {
+	HANDLE osfhnd;
+	char osflags;
+} ioinfo;
+
+extern __declspec(dllimport) ioinfo *__pioinfo[];
+
+static size_t sizeof_ioinfo = 0;
+
+#define IOINFO_L2E 5
+#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
+
+#define FDEV  0x40
+
+static inline ioinfo* _pioinfo(int fd)
 {
-	/* get original console handle */
-	int fd = _fileno(stream);
-	HANDLE hcon = (HANDLE) _get_osfhandle(fd);
-	if (hcon == INVALID_HANDLE_VALUE)
-		die_errno("_get_osfhandle(%i) failed", fd);
+	return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
+			(fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
+}
 
-	/* save a copy to phcon and console (used by the background thread) */
-	console = *phcon = duplicate_handle(hcon);
+static int init_sizeof_ioinfo()
+{
+	int istty, wastty;
+	/* don't init twice */
+	if (sizeof_ioinfo)
+		return sizeof_ioinfo >= 256;
 
-	/* duplicate new_fd over fd (closes fd and associated handle (hcon)) */
-	if (_dup2(new_fd, fd))
-		die_errno("_dup2(%i, %i) failed", new_fd, fd);
+	sizeof_ioinfo = sizeof(ioinfo);
+	wastty = isatty(1);
+	while (sizeof_ioinfo < 256) {
+		/* toggle FDEV flag, check isatty, then toggle back */
+		_pioinfo(1)->osflags ^= FDEV;
+		istty = isatty(1);
+		_pioinfo(1)->osflags ^= FDEV;
+		/* return if we found the correct size */
+		if (istty != wastty)
+			return 0;
+		sizeof_ioinfo += sizeof(void*);
+	}
+	error("Tweaking file descriptors doesn't work with this MSVCRT.dll");
+	return 1;
+}
 
-	/* no buffering, or stdout / stderr will be out of sync */
-	setbuf(stream, NULL);
-	return (HANDLE) _get_osfhandle(fd);
+static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
+{
+	ioinfo *pioinfo;
+	HANDLE old_handle;
+
+	/* init ioinfo size if we haven't done so */
+	if (init_sizeof_ioinfo())
+		return INVALID_HANDLE_VALUE;
+
+	/* get ioinfo pointer and change the handles */
+	pioinfo = _pioinfo(fd);
+	old_handle = pioinfo->osfhnd;
+	pioinfo->osfhnd = new_handle;
+	return old_handle;
 }
 
 void winansi_init(void)
 {
-	int con1, con2, hwrite_fd;
+	int con1, con2;
 	char name[32];
 
 	/* check if either stdout or stderr is a console output screen buffer */
@@ -514,19 +561,11 @@ void winansi_init(void)
 	if (atexit(winansi_exit))
 		die_errno("atexit(winansi_exit) failed");
 
-	/* create a file descriptor for the write end of the pipe */
-	hwrite_fd = _open_osfhandle((long) duplicate_handle(hwrite), _O_BINARY);
-	if (hwrite_fd == -1)
-		die_errno("_open_osfhandle(%li) failed", (long) hwrite);
-
 	/* redirect stdout / stderr to the pipe */
 	if (con1)
-		hwrite1 = redirect_console(stdout, &hconsole1, hwrite_fd);
+		hconsole1 = swap_osfhnd(1, hwrite1 = duplicate_handle(hwrite));
 	if (con2)
-		hwrite2 = redirect_console(stderr, &hconsole2, hwrite_fd);
-
-	/* close pipe file descriptor (also closes the duped hwrite) */
-	close(hwrite_fd);
+		hconsole2 = swap_osfhnd(2, hwrite2 = duplicate_handle(hwrite));
 }
 
 static int is_same_handle(HANDLE hnd, int fd)
@@ -534,19 +573,6 @@ static int is_same_handle(HANDLE hnd, int fd)
 	return hnd != INVALID_HANDLE_VALUE && hnd == (HANDLE) _get_osfhandle(fd);
 }
 
-/*
- * Return true if stdout / stderr is a pipe redirecting to the console.
- */
-int winansi_isatty(int fd)
-{
-	if (fd == 1 && is_same_handle(hwrite1, 1))
-		return 1;
-	else if (fd == 2 && is_same_handle(hwrite2, 2))
-		return 1;
-	else
-		return isatty(fd);
-}
-
 /*
  * Returns the real console handle if stdout / stderr is a pipe redirecting
  * to the console. Allows spawn / exec to pass the console to the next process.

From de8dec8c1bfca374e03918e32816379603f79c5f Mon Sep 17 00:00:00 2001
From: Karsten Blees 
Date: Fri, 7 Jan 2011 17:20:21 +0100
Subject: [PATCH 3689/3720] MSVC: link dynamically to the CRT

Dynamic linking is generally preferred over static linking, and MSVCRT.dll
has been integral part of Windows for a long time.

This also fixes linker warnings for _malloc and _free in zlib.lib, which
seems to be compiled for MSVCRT.dll already.

The DLL version also exports some of the CRT initialization functions,
which are hidden in the static libcmt.lib (e.g. __wgetmainargs, required by
subsequent Unicode patches).

Signed-off-by: Karsten Blees 
---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 53665cbc69..3571a4a6d6 100644
--- a/Makefile
+++ b/Makefile
@@ -1248,16 +1248,16 @@ ifeq ($(uname_S),Windows)
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/poll.o compat/win32/dirent.o
 	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
-	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
+	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
 	EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 	PTHREAD_LIBS =
 	lib =
 ifndef DEBUG
-	BASIC_CFLAGS += -GL -Os -MT
+	BASIC_CFLAGS += -GL -Os -MD
 	BASIC_LDFLAGS += -LTCG
 	AR += -LTCG
 else
-	BASIC_CFLAGS += -Zi -MTd
+	BASIC_CFLAGS += -Zi -MDd
 endif
 	X = .exe
 endif

From 8efbce376b4d9cafa63884ae27ae1620646f8954 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:45:18 -0500
Subject: [PATCH 3690/3720] MSVC: fix poll-related macro redefines

This seems to be related to the poll-emulation... I see that these things
are guarded by an "#if(_WIN32_WINNT >= 0x0600)" in , which
means it's supported for Windows Vista and above... We still support
Windows XP, so it seems someone has set this too high :)

I'd prefer to set this from the Makefile, but this generates a warning in
compat/win32/poll.c about redefining a macro (poll.c wants it to be 0x502,
which is Windows XP with SP2, rather than 0x501 which is normal Windows
XP).

Signed-off-by: Johannes Schindelin 
---
 compat/mingw.h    | 1 +
 git-compat-util.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index 18bf5fd2ce..8c46a5c76b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,3 +1,4 @@
+#define _WIN32_WINNT 0x0501
 #include 
 #include 
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 39866a76c2..76c5eef420 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
 #define _SGI_SOURCE 1
 
 #ifdef WIN32 /* Both MinGW and MSVC */
+#define _WIN32_WINNT 0x0501
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include 
 #include 

From 34f1712f48f927b55eaeac5124dbedbdb2c169c3 Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund 
Date: Tue, 1 Nov 2011 12:54:30 -0500
Subject: [PATCH 3691/3720] MSVC: require pton and ntop emulation

Without this, git-daemon cannot be built with Microsoft Visual C++.

Signed-off-by: Johannes Schindelin 
---
 Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile b/Makefile
index 3571a4a6d6..7fcc056b47 100644
--- a/Makefile
+++ b/Makefile
@@ -1236,6 +1236,8 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	NO_POSIX_GOODIES = UnfortunatelyYes
 	NATIVE_CRLF = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease

From c00fe59ae266128cbf16ca710d12a3eafbe9459f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 15:55:26 +0200
Subject: [PATCH 3692/3720] fast-export: do not refer to non-existing marks

When calling `git fast-export a..a b` when a and b refer to the same
commit, nothing would be exported, and an incorrect reset line would
be printed for b ('from :0').

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 19509ea754..b0891b3735 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -529,9 +529,20 @@ static void get_tags_and_duplicates(struct object_array *pending,
 	}
 }
 
+static void handle_reset(const char *name, struct object *object)
+{
+	int mark = get_object_mark(object);
+
+	if (mark)
+		printf("reset %s\nfrom :%d\n\n", name,
+		       get_object_mark(object));
+	else
+		printf("reset %s\nfrom %s\n\n", name,
+		       sha1_to_hex(object->sha1));
+}
+
 static void handle_tags_and_duplicates(struct string_list *extra_refs)
 {
-	struct commit *commit;
 	int i;
 
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
@@ -543,9 +554,7 @@ static void handle_tags_and_duplicates(struct string_list *extra_refs)
 			break;
 		case OBJ_COMMIT:
 			/* create refs pointing to already seen commits */
-			commit = (struct commit *)object;
-			printf("reset %s\nfrom :%d\n\n", name,
-			       get_object_mark(&commit->object));
+			handle_reset(name, object);
 			show_progress();
 			break;
 		}

From 07d38c314eb5d8f7420d71a95f3d7bcd33a80d95 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 17:14:47 +0200
Subject: [PATCH 3693/3720] setup_revisions: remember whether a ref was
 positive or not

This will be required by fast-export, when no commits were
exported, but the refs should be set, of course.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 object.h   |  2 +-
 revision.c | 12 +++++++-----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/object.h b/object.h
index 6a97b6ba1a..0001752c6d 100644
--- a/object.h
+++ b/object.h
@@ -12,7 +12,7 @@ struct object_array {
 	struct object_array_entry {
 		struct object *item;
 		const char *name;
-		unsigned mode;
+		unsigned mode, flags;
 	} *objects;
 };
 
diff --git a/revision.c b/revision.c
index 935e7a7ba4..206a5b69fe 100644
--- a/revision.c
+++ b/revision.c
@@ -185,7 +185,7 @@ void mark_parents_uninteresting(struct commit *commit)
 	}
 }
 
-static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
+static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode, unsigned flags)
 {
 	if (!obj)
 		return;
@@ -206,11 +206,12 @@ static void add_pending_object_with_mode(struct rev_info *revs, struct object *o
 			return;
 	}
 	add_object_array_with_mode(obj, name, &revs->pending, mode);
+	revs->pending.objects[revs->pending.nr-1].flags = flags;
 }
 
 void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
 {
-	add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
+	add_pending_object_with_mode(revs, obj, name, S_IFINVALID, 0);
 }
 
 void add_head_to_pending(struct rev_info *revs)
@@ -1176,7 +1177,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
 					REV_CMD_LEFT, a_flags);
 			add_rev_cmdline(revs, &b->object, next,
 					REV_CMD_RIGHT, flags);
-			add_pending_object(revs, &a->object, this);
+			add_pending_object_with_mode(revs, &a->object, this,
+						     S_IFINVALID, flags_exclude);
 			add_pending_object(revs, &b->object, next);
 			return 0;
 		}
@@ -1207,7 +1209,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
 		verify_non_filename(revs->prefix, arg);
 	object = get_reference(revs, arg, sha1, flags ^ local_flags);
 	add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
-	add_pending_object_with_mode(revs, object, arg, mode);
+	add_pending_object_with_mode(revs, object, arg, mode, local_flags);
 	return 0;
 }
 
@@ -1824,7 +1826,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 		if (get_sha1_with_mode(revs->def, sha1, &mode))
 			die("bad default revision '%s'", revs->def);
 		object = get_reference(revs, revs->def, sha1, 0);
-		add_pending_object_with_mode(revs, object, revs->def, mode);
+		add_pending_object_with_mode(revs, object, revs->def, mode, 0);
 	}
 
 	/* Did the user ask for any diff output? Run the diff! */

From 9d4e684f326fddaa03dd4aec2e4c29278c1364c9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 15:40:23 +0200
Subject: [PATCH 3694/3720] fast-export: do not export negative refs

When calling `git fast-export master..next` we want to export
refs/heads/next, but not refs/heads/master.

Currently this is not a problem, because negative refs' commits
are never shown. In the next commit this will be changed in order
to make sure that 'master..master' does export master. I.e. even
refs whose commits are not shown are exported.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index b0891b3735..0dc5124675 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -484,7 +484,7 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		struct commit *commit = commit;
 		char *full_name;
 
-		if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
+		if ((e->flags & UNINTERESTING) || dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
 			continue;
 
 		switch (e->item->type) {

From c5aa22b7fe3636a6a9537ab4f53fee5bd8d3ad15 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 23 Jul 2011 17:14:47 +0200
Subject: [PATCH 3695/3720] setup_revisions: remember whether a ref was
 positive or not

This will be required by fast-export, when no commits were
exported, but the refs should be set, of course.

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/fast-export.c  | 36 +++++++++++++++++++++++++++++++-----
 t/t9350-fast-export.sh |  2 +-
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 0dc5124675..137792d49d 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -18,6 +18,8 @@
 #include "parse-options.h"
 #include "quote.h"
 
+#define REF_HANDLED (ALL_REV_FLAGS + 1)
+
 static const char *fast_export_usage[] = {
 	"git fast-export [rev-list-opts]",
 	NULL
@@ -473,6 +475,7 @@ static void handle_tag(const char *name, struct tag *tag)
 }
 
 static void get_tags_and_duplicates(struct object_array *pending,
+				    struct string_list *refs,
 				    struct string_list *extra_refs)
 {
 	struct tag *tag;
@@ -524,8 +527,11 @@ static void get_tags_and_duplicates(struct object_array *pending,
 		if (commit->util)
 			/* more than one name for the same object */
 			string_list_append(extra_refs, full_name)->util = commit;
-		else
+		else {
 			commit->util = full_name;
+			/* we might need to set this ref explicitly */
+			string_list_append(refs, full_name)->util = commit;
+		}
 	}
 }
 
@@ -541,10 +547,29 @@ static void handle_reset(const char *name, struct object *object)
 		       sha1_to_hex(object->sha1));
 }
 
-static void handle_tags_and_duplicates(struct string_list *extra_refs)
+static void handle_tags_and_duplicates(struct string_list *refs, struct string_list *extra_refs)
 {
 	int i;
 
+	/* even if no commits were exported, we need to export the ref */
+	for (i = refs->nr - 1; i >= 0; i--) {
+		const char *name = refs->items[i].string;
+		struct object *object = refs->items[i].util;
+
+		if (!(object->flags & REF_HANDLED)) {
+			if (object->type & OBJ_TAG)
+				handle_tag(name, (struct tag *)object);
+			else {
+				if (!prefixcmp(name, "refs/tags/") &&
+				    (tag_of_filtered_mode != REWRITE ||
+				     !get_object_mark(object)))
+					continue;
+				handle_reset(name, object);
+				object->flags |= REF_HANDLED;
+			}
+		}
+	}
+
 	for (i = extra_refs->nr - 1; i >= 0; i--) {
 		const char *name = extra_refs->items[i].string;
 		struct object *object = extra_refs->items[i].util;
@@ -634,7 +659,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info revs;
 	struct object_array commits = OBJECT_ARRAY_INIT;
-	struct string_list extra_refs = STRING_LIST_INIT_NODUP;
+	struct string_list refs = STRING_LIST_INIT_NODUP, extra_refs = STRING_LIST_INIT_NODUP;
 	struct commit *commit;
 	char *export_filename = NULL, *import_filename = NULL;
 	struct option options[] = {
@@ -684,7 +709,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 	if (import_filename && revs.prune_data.nr)
 		full_tree = 1;
 
-	get_tags_and_duplicates(&revs.pending, &extra_refs);
+	get_tags_and_duplicates(&revs.pending, &refs, &extra_refs);
 
 	if (prepare_revision_walk(&revs))
 		die("revision walk setup failed");
@@ -696,11 +721,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 		}
 		else {
 			handle_commit(commit, &revs);
+			commit->object.flags |= REF_HANDLED;
 			handle_tail(&commits, &revs);
 		}
 	}
 
-	handle_tags_and_duplicates(&extra_refs);
+	handle_tags_and_duplicates(&refs, &extra_refs);
 
 	if (export_filename)
 		export_marks(export_filename);
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 57569a7eed..e47b7ac879 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -446,7 +446,7 @@ from $(git rev-parse master)
 
 EOF
 
-test_expect_failure 'refs are updated even if no commits need to be exported' '
+test_expect_success 'refs are updated even if no commits need to be exported' '
 	git fast-export master..master > actual &&
 	test_cmp expected actual
 '

From 7255736c70705de105a4543e7d5a7bbbef7ddb29 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Fri, 15 Jul 2011 16:37:28 +0200
Subject: [PATCH 3696/3720] t5800: test pushing a new branch with old content

This works now that fast-export has been fixed to properly handle
refs that point to a commit that was not exported during the current
fast-export run.
---
 t/t5800-remote-helpers.sh | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index d1fecda1d2..49e8c37ced 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -138,6 +138,14 @@ test_expect_success 'push new branch by name' '
 	compare_refs clone HEAD server refs/heads/new-name
 '
 
+test_expect_failure 'push new branch with old content' '
+	(cd clone &&
+	 git checkout -b existing &&
+	 git push origin existing
+	) &&
+	compare_refs clone refs/heads/existing server refs/heads/existing
+'
+
 test_expect_failure 'push new branch with old:new refspec' '
 	(cd clone &&
 	 git push origin new-name:new-refspec

From e9c6b8b2bc93f7e215a6258a32b9e94efa0c5ae9 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Fri, 15 Jul 2011 21:55:01 +0200
Subject: [PATCH 3697/3720] t5800: point out that deleting branches does not
 work

This test actually breaks the repositories involved somehow, so it is
not enabled by default.
---
 t/t5800-remote-helpers.sh | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh
index 49e8c37ced..2949b4548b 100755
--- a/t/t5800-remote-helpers.sh
+++ b/t/t5800-remote-helpers.sh
@@ -138,7 +138,7 @@ test_expect_success 'push new branch by name' '
 	compare_refs clone HEAD server refs/heads/new-name
 '
 
-test_expect_failure 'push new branch with old content' '
+test_expect_success 'push new branch with old content' '
 	(cd clone &&
 	 git checkout -b existing &&
 	 git push origin existing
@@ -146,6 +146,17 @@ test_expect_failure 'push new branch with old content' '
 	compare_refs clone refs/heads/existing server refs/heads/existing
 '
 
+test_expect_failure BROKEN 'delete branch' '
+	(cd clone &&
+	 git checkout -b delete-me &&
+	 echo content >>file &&
+	 git commit -a -m eight &&
+	 git push origin delete-me
+	 git push origin :delete-me) &&
+	test_must_fail git --git-dir="server/.git" rev-parse --verify delete-me
+'
+
+
 test_expect_failure 'push new branch with old:new refspec' '
 	(cd clone &&
 	 git push origin new-name:new-refspec

From 7724ddc461cdf7f382c8400281baa50103c2f698 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sat, 28 Aug 2010 20:49:01 -0500
Subject: [PATCH 3698/3720] transport-helper: add trailing --

---
 transport-helper.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/transport-helper.c b/transport-helper.c
index 61c928f6cd..57069432ab 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -398,7 +398,7 @@ static int get_exporter(struct transport *transport,
 	/* we need to duplicate helper->in because we want to use it after
 	 * fastexport is done with it. */
 	fastexport->out = dup(helper->in);
-	fastexport->argv = xcalloc(5 + revlist_args->nr, sizeof(*fastexport->argv));
+	fastexport->argv = xcalloc(6 + revlist_args->nr, sizeof(*fastexport->argv));
 	fastexport->argv[argc++] = "fast-export";
 	fastexport->argv[argc++] = "--use-done-feature";
 	if (data->export_marks)
@@ -409,6 +409,8 @@ static int get_exporter(struct transport *transport,
 	for (i = 0; i < revlist_args->nr; i++)
 		fastexport->argv[argc++] = revlist_args->items[i].string;
 
+	fastexport->argv[argc++] = "--";
+
 	fastexport->git_cmd = 1;
 	return start_command(fastexport);
 }

From e1aef601194804a7516e6053ee32a263a8e01cd6 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 00:06:00 +0200
Subject: [PATCH 3699/3720] remote-helper: check helper status after
 import/export

Signed-off-by: Johannes Schindelin 
Signed-off-by: Sverre Rabbelier 
---
 builtin/clone.c    |  4 +++-
 transport-helper.c | 16 ++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index a4d8d25ee3..20efd2fe79 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -821,7 +821,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 			}
 
 		if (!is_local && !complete_refs_before_fetch)
-			transport_fetch_refs(transport, mapped_refs);
+			if (transport_fetch_refs(transport, mapped_refs))
+				die(_("could not fetch refs from %s"),
+				    transport->url);
 
 		remote_head = find_ref_by_name(refs, "HEAD");
 		remote_head_points_at =
diff --git a/transport-helper.c b/transport-helper.c
index 57069432ab..3b6a9fa53d 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -415,6 +415,19 @@ static int get_exporter(struct transport *transport,
 	return start_command(fastexport);
 }
 
+static void check_helper_status(struct helper_data *data)
+{
+	int pid, status;
+
+	pid = waitpid(data->helper->pid, &status, WNOHANG);
+	if (pid < 0)
+		die("Could not retrieve status of remote helper '%s'",
+		    data->name);
+	if (pid > 0 && WIFEXITED(status))
+		die("Remote helper '%s' died with %d",
+		    data->name, WEXITSTATUS(status));
+}
+
 static int fetch_with_import(struct transport *transport,
 			     int nr_heads, struct ref **to_fetch)
 {
@@ -443,6 +456,8 @@ static int fetch_with_import(struct transport *transport,
 
 	if (finish_command(&fastimport))
 		die("Error while running fast-import");
+	check_helper_status(data);
+
 	free(fastimport.argv);
 	fastimport.argv = NULL;
 
@@ -771,6 +786,7 @@ static int push_refs_with_export(struct transport *transport,
 
 	if (finish_command(&exporter))
 		die("Error while running fast-export");
+	check_helper_status(data);
 	push_update_refs_status(data, remote_refs);
 	return 0;
 }

From 6ebecf6dab7942a105747e0446e0378cc17d24cc Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 00:11:18 +0200
Subject: [PATCH 3700/3720] remote-testgit: factor out RemoteHelper class

Facilitate writing import-export based helpers in python by
refactoring common code to a base class.

[jes: rebased to newer upstream Git]

Signed-off-by: Sverre Rabbelier 
Signed-off-by: Johannes Schindelin 
---
 git-remote-testgit.py              | 295 ++++++-----------------------
 git_remote_helpers/git/importer.py |  28 +--
 git_remote_helpers/helper.py       | 207 ++++++++++++++++++++
 3 files changed, 267 insertions(+), 263 deletions(-)
 create mode 100644 git_remote_helpers/helper.py

diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index 5f3ebd244d..d57c1dc393 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -1,272 +1,95 @@
 #!/usr/bin/env python
 
-# This command is a simple remote-helper, that is used both as a
-# testcase for the remote-helper functionality, and as an example to
-# show remote-helper authors one possible implementation.
-#
-# This is a Git <-> Git importer/exporter, that simply uses git
-# fast-import and git fast-export to consume and produce fast-import
-# streams.
-#
-# To understand better the way things work, one can activate debug
-# traces by setting (to any value) the environment variables
-# GIT_TRANSPORT_HELPER_DEBUG and GIT_DEBUG_TESTGIT, to see messages
-# from the transport-helper side, or from this example remote-helper.
-
-# hashlib is only available in python >= 2.5
-try:
-    import hashlib
-    _digest = hashlib.sha1
-except ImportError:
-    import sha
-    _digest = sha.new
 import sys
 import os
-import time
 sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
 
-from git_remote_helpers.util import die, debug, warn
+from git_remote_helpers.helper import RemoteHelper
+from git_remote_helpers.util import check_output, debug
 from git_remote_helpers.git.repo import GitRepo
 from git_remote_helpers.git.exporter import GitExporter
 from git_remote_helpers.git.importer import GitImporter
 from git_remote_helpers.git.non_local import NonLocalGit
 
-def get_repo(alias, url):
-    """Returns a git repository object initialized for usage.
-    """
 
-    repo = GitRepo(url)
-    repo.get_revs()
-    repo.get_head()
+class TestgitRemoteHelper(RemoteHelper):
+    def get_repo(self, alias, url):
+        """Returns a git repository object initialized for usage.
+        """
 
-    hasher = _digest()
-    hasher.update(repo.path)
-    repo.hash = hasher.hexdigest()
+        repo = GitRepo(url)
+        repo.get_revs()
+        repo.get_head()
 
-    repo.get_base_path = lambda base: os.path.join(
-        base, 'info', 'fast-import', repo.hash)
+        prefix = 'refs/testgit/%s/' % alias
+        debug("prefix: '%s'", prefix)
 
-    prefix = 'refs/testgit/%s/' % alias
-    debug("prefix: '%s'", prefix)
+        repo.marksfile = 'testgit.marks'
+        repo.prefix = prefix
 
-    repo.gitdir = os.environ["GIT_DIR"]
-    repo.alias = alias
-    repo.prefix = prefix
+        self.setup_repo(repo, alias)
 
-    repo.exporter = GitExporter(repo)
-    repo.importer = GitImporter(repo)
-    repo.non_local = NonLocalGit(repo)
+        repo.exporter = GitExporter(repo)
+        repo.importer = GitImporter(repo)
+        repo.non_local = NonLocalGit(repo)
 
-    return repo
-
-
-def local_repo(repo, path):
-    """Returns a git repository object initalized for usage.
-    """
-
-    local = GitRepo(path)
-
-    local.non_local = None
-    local.gitdir = repo.gitdir
-    local.alias = repo.alias
-    local.prefix = repo.prefix
-    local.hash = repo.hash
-    local.get_base_path = repo.get_base_path
-    local.exporter = GitExporter(local)
-    local.importer = GitImporter(local)
-
-    return local
-
-
-def do_capabilities(repo, args):
-    """Prints the supported capabilities.
-    """
-
-    print "import"
-    print "export"
-    print "refspec refs/heads/*:%s*" % repo.prefix
-
-    dirname = repo.get_base_path(repo.gitdir)
-
-    if not os.path.exists(dirname):
-        os.makedirs(dirname)
-
-    path = os.path.join(dirname, 'testgit.marks')
-
-    print "*export-marks %s" % path
-    if os.path.exists(path):
-        print "*import-marks %s" % path
-
-    print # end capabilities
-
-
-def do_list(repo, args):
-    """Lists all known references.
-
-    Bug: This will always set the remote head to master for non-local
-    repositories, since we have no way of determining what the remote
-    head is at clone time.
-    """
-
-    for ref in repo.revs:
-        debug("? refs/heads/%s", ref)
-        print "? refs/heads/%s" % ref
-
-    if repo.head:
-        debug("@refs/heads/%s HEAD" % repo.head)
-        print "@refs/heads/%s HEAD" % repo.head
-    else:
-        debug("@refs/heads/master HEAD")
-        print "@refs/heads/master HEAD"
-
-    print # end list
-
-
-def update_local_repo(repo):
-    """Updates (or clones) a local repo.
-    """
-
-    if repo.local:
         return repo
 
-    path = repo.non_local.clone(repo.gitdir)
-    repo.non_local.update(repo.gitdir)
-    repo = local_repo(repo, path)
-    return repo
+    def local_repo(self, repo, path):
+        """Returns a git repository object initalized for usage.
+        """
 
+        local = GitRepo(path)
 
-def do_import(repo, args):
-    """Exports a fast-import stream from testgit for git to import.
-    """
+        self.setup_local_repo(local, repo)
 
-    if len(args) != 1:
-        die("Import needs exactly one ref")
+        local.exporter = GitExporter(local)
+        local.importer = GitImporter(local)
 
-    if not repo.gitdir:
-        die("Need gitdir to import")
+        return local
 
-    ref = args[0]
-    refs = [ref]
+    def do_list(self, repo, args):
+        """Lists all known references.
 
-    while True:
-        line = sys.stdin.readline()
-        if line == '\n':
-            break
-        if not line.startswith('import '):
-            die("Expected import line.")
+        Bug: This will always set the remote head to master for non-local
+        repositories, since we have no way of determining what the remote
+        head is at clone time.
+        """
 
-        # strip of leading 'import '
-        ref = line[7:].strip()
-        refs.append(ref)
+        for ref in repo.revs:
+            debug("? refs/heads/%s", ref)
+            print "? refs/heads/%s" % ref
 
-    repo = update_local_repo(repo)
-    repo.exporter.export_repo(repo.gitdir, refs)
+        if repo.head:
+            debug("@refs/heads/%s HEAD" % repo.head)
+            print "@refs/heads/%s HEAD" % repo.head
+        else:
+            debug("@refs/heads/master HEAD")
+            print "@refs/heads/master HEAD"
 
-    print "done"
+        print # end list
 
+    def sanitize(self, value):
+        """Cleans up the url.
+        """
 
-def do_export(repo, args):
-    """Imports a fast-import stream from git to testgit.
-    """
+        if value.startswith('testgit::'):
+            value = value[9:]
 
-    if not repo.gitdir:
-        die("Need gitdir to export")
+        return value
 
-    update_local_repo(repo)
-    changed = repo.importer.do_import(repo.gitdir)
+    def get_refs(self, repo, gitdir):
+        """Returns a dictionary with refs.
+        """
+        args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
+        lines = check_output(args).strip().split('\n')
+        refs = {}
+        for line in lines:
+            value, name = line.split(' ')
+            name = name.strip('commit\t')
+            refs[name] = value
+        return refs
 
-    if not repo.local:
-        repo.non_local.push(repo.gitdir)
-
-    for ref in changed:
-        print "ok %s" % ref
-    print
-
-
-COMMANDS = {
-    'capabilities': do_capabilities,
-    'list': do_list,
-    'import': do_import,
-    'export': do_export,
-}
-
-
-def sanitize(value):
-    """Cleans up the url.
-    """
-
-    if value.startswith('testgit::'):
-        value = value[9:]
-
-    return value
-
-
-def read_one_line(repo):
-    """Reads and processes one command.
-    """
-
-    sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
-    if sleepy:
-        debug("Sleeping %d sec before readline" % int(sleepy))
-        time.sleep(int(sleepy))
-
-    line = sys.stdin.readline()
-
-    cmdline = line
-
-    if not cmdline:
-        warn("Unexpected EOF")
-        return False
-
-    cmdline = cmdline.strip().split()
-    if not cmdline:
-        # Blank line means we're about to quit
-        return False
-
-    cmd = cmdline.pop(0)
-    debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
-
-    if cmd not in COMMANDS:
-        die("Unknown command, %s", cmd)
-
-    func = COMMANDS[cmd]
-    func(repo, cmdline)
-    sys.stdout.flush()
-
-    return True
-
-
-def main(args):
-    """Starts a new remote helper for the specified repository.
-    """
-
-    if len(args) != 3:
-        die("Expecting exactly three arguments.")
-        sys.exit(1)
-
-    if os.getenv("GIT_DEBUG_TESTGIT"):
-        import git_remote_helpers.util
-        git_remote_helpers.util.DEBUG = True
-
-    alias = sanitize(args[1])
-    url = sanitize(args[2])
-
-    if not alias.isalnum():
-        warn("non-alnum alias '%s'", alias)
-        alias = "tmp"
-
-    args[1] = alias
-    args[2] = url
-
-    repo = get_repo(alias, url)
-
-    debug("Got arguments %s", args[1:])
-
-    more = True
-
-    sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
-    while (more):
-        more = read_one_line(repo)
 
 if __name__ == '__main__':
-    sys.exit(main(sys.argv))
+    sys.exit(TestgitRemoteHelper().main(sys.argv))
diff --git a/git_remote_helpers/git/importer.py b/git_remote_helpers/git/importer.py
index 5c6b595e16..02a719ac02 100644
--- a/git_remote_helpers/git/importer.py
+++ b/git_remote_helpers/git/importer.py
@@ -1,7 +1,7 @@
 import os
 import subprocess
 
-from git_remote_helpers.util import check_call, check_output
+from git_remote_helpers.util import check_call
 
 
 class GitImporter(object):
@@ -16,18 +16,6 @@ class GitImporter(object):
 
         self.repo = repo
 
-    def get_refs(self, gitdir):
-        """Returns a dictionary with refs.
-        """
-        args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
-        lines = check_output(args).strip().split('\n')
-        refs = {}
-        for line in lines:
-            value, name = line.split(' ')
-            name = name.strip('commit\t')
-            refs[name] = value
-        return refs
-
     def do_import(self, base):
         """Imports a fast-import stream to the given directory.
 
@@ -44,23 +32,9 @@ class GitImporter(object):
         if not os.path.exists(dirname):
             os.makedirs(dirname)
 
-        refs_before = self.get_refs(gitdir)
-
         args = ["git", "--git-dir=" + gitdir, "fast-import", "--quiet", "--export-marks=" + path]
 
         if os.path.exists(path):
             args.append("--import-marks=" + path)
 
         check_call(args)
-
-        refs_after = self.get_refs(gitdir)
-
-        changed = {}
-
-        for name, value in refs_after.iteritems():
-            if refs_before.get(name) == value:
-                continue
-
-            changed[name] = value
-
-        return changed
diff --git a/git_remote_helpers/helper.py b/git_remote_helpers/helper.py
new file mode 100644
index 0000000000..56ed1dad5b
--- /dev/null
+++ b/git_remote_helpers/helper.py
@@ -0,0 +1,207 @@
+import os
+import sys
+import time
+
+# hashlib is only available in python >= 2.5
+try:
+    import hashlib
+    _digest = hashlib.sha1
+except ImportError:
+    import sha
+    _digest = sha.new
+
+from git_remote_helpers.util import debug, die, warn
+
+
+class RemoteHelper(object):
+    def __init__(self):
+        self.commands = {
+            'capabilities': self.do_capabilities,
+            'list': self.do_list,
+            'import': self.do_import,
+            'export': self.do_export,
+        }
+
+    def setup_repo(self, repo, alias):
+        """Returns a git repository object initialized for usage.
+        """
+
+        hasher = _digest()
+        hasher.update(repo.path)
+        repo.hash = hasher.hexdigest()
+
+        repo.get_base_path = lambda base: os.path.join(
+            base, 'info', 'fast-import', repo.hash)
+
+        repo.gitdir = os.environ["GIT_DIR"]
+        repo.alias = alias
+
+    def setup_local_repo(self, local, repo):
+        """Returns a git repository object initalized for usage.
+        """
+        local.non_local = None
+        local.gitdir = repo.gitdir
+        local.alias = repo.alias
+        local.prefix = repo.prefix
+        local.hash = repo.hash
+        local.get_base_path = repo.get_base_path
+
+    def do_capabilities(self, repo, args):
+        """Prints the supported capabilities.
+        """
+
+        print "import"
+        print "export"
+        print "refspec refs/heads/*:%s*" % repo.prefix
+
+        dirname = repo.get_base_path(repo.gitdir)
+
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+
+        path = os.path.join(dirname, repo.marksfile)
+
+        print "*export-marks %s" % path
+        if os.path.exists(path):
+            print "*import-marks %s" % path
+
+        print # end capabilities
+
+    def update_local_repo(self, repo):
+        """Updates (or clones) a local repo.
+        """
+
+        if repo.local:
+            return repo
+
+        path = repo.non_local.clone(repo.gitdir)
+        repo.non_local.update(repo.gitdir)
+        repo = self.local_repo(repo, path)
+        return repo
+
+    def do_import(self, repo, args):
+        """Exports a fast-import stream from testgit for git to import.
+        """
+
+        if len(args) != 1:
+            die("Import needs exactly one ref")
+
+        if not repo.gitdir:
+            die("Need gitdir to import")
+
+        ref = args[0]
+        refs = [ref]
+
+        while True:
+            line = sys.stdin.readline()
+            if line == '\n':
+                break
+            if not line.startswith('import '):
+                die("Expected import line.")
+
+            # strip of leading 'import '
+            ref = line[7:].strip()
+            refs.append(ref)
+
+        repo = self.update_local_repo(repo)
+
+        repo.exporter.export_repo(repo.gitdir, refs)
+
+        print "done"
+
+    def do_export(self, repo, args):
+        """Imports a fast-import stream from git to testgit.
+        """
+
+        if not repo.gitdir:
+            die("Need gitdir to export")
+
+        localrepo = self.update_local_repo(repo)
+
+        refs_before = self.get_refs(repo, repo.gitdir)
+        localrepo.importer.do_import(localrepo.gitdir)
+        refs_after = self.get_refs(repo, repo.gitdir)
+
+        changed = {}
+
+        for name, value in refs_after.iteritems():
+            if refs_before.get(name) == value:
+                continue
+
+            changed[name] = value
+
+        if not repo.local:
+            repo.non_local.push(repo.gitdir)
+
+        for ref in changed:
+            print "ok %s" % ref
+        print
+
+    def read_one_line(self, repo):
+        """Reads and processes one command.
+        """
+
+        sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
+        if sleepy:
+            debug("Sleeping %d sec before readline" % int(sleepy))
+            time.sleep(int(sleepy))
+
+        line = sys.stdin.readline()
+
+        cmdline = line
+
+        if not cmdline:
+            warn("Unexpected EOF")
+            return False
+
+        cmdline = cmdline.strip().split()
+        if not cmdline:
+            # Blank line means we're about to quit
+            return False
+
+        cmd = cmdline.pop(0)
+        debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
+
+        if cmd not in self.commands:
+            die("Unknown command, %s", cmd)
+
+        func = self.commands[cmd]
+        func(repo, cmdline)
+        sys.stdout.flush()
+
+        return True
+
+    def main(self, args):
+        """Starts a new remote helper for the specified repository.
+        """
+
+        if len(args) != 3:
+            die("Expecting exactly three arguments.")
+            sys.exit(1)
+
+        if os.getenv("GIT_REMOTE_HELPER_DEBUG"):
+            import git_remote_helpers.util
+            git_remote_helpers.util.DEBUG = True
+
+        alias = self.sanitize(args[1])
+        url = self.sanitize(args[2])
+
+        if not alias.isalnum():
+            warn("non-alnum alias '%s'", alias)
+            alias = "tmp"
+
+        args[1] = alias
+        args[2] = url
+
+        repo = self.get_repo(alias, url)
+
+        debug("Got arguments %s", args[1:])
+
+        more = True
+
+        sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
+        while (more):
+            more = self.read_one_line(repo)
+
+    if __name__ == '__main__':
+        sys.exit(main(sys.argv))

From 1fc80e1c0dea62b7b2c495ce70c8007c862fc607 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 13:43:34 +0200
Subject: [PATCH 3701/3720] git-remote-testgit: make local a function

Other helpers (such as git-remote-hg) require that 'self.local' is a
function, rather than a variable.
---
 git_remote_helpers/git/importer.py | 2 +-
 git_remote_helpers/git/repo.py     | 6 +++---
 git_remote_helpers/helper.py       | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/git_remote_helpers/git/importer.py b/git_remote_helpers/git/importer.py
index 02a719ac02..b7d6107933 100644
--- a/git_remote_helpers/git/importer.py
+++ b/git_remote_helpers/git/importer.py
@@ -23,7 +23,7 @@ class GitImporter(object):
         """
 
         dirname = self.repo.get_base_path(base)
-        if self.repo.local:
+        if self.repo.local():
             gitdir = self.repo.gitpath
         else:
             gitdir = os.path.abspath(os.path.join(dirname, '.git'))
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
index acbf8d7785..4536233868 100644
--- a/git_remote_helpers/git/repo.py
+++ b/git_remote_helpers/git/repo.py
@@ -38,14 +38,14 @@ class GitRepo(object):
         self.path = path
         self.head = None
         self.revmap = {}
-        self.local = not is_remote(self.path)
+        self.local = lambda: not is_remote(self.path)
 
         if(self.path.endswith('.git')):
             self.gitpath = self.path
         else:
             self.gitpath = os.path.join(self.path, '.git')
 
-        if self.local and not os.path.exists(self.gitpath):
+        if self.local() and not os.path.exists(self.gitpath):
             os.makedirs(self.gitpath)
 
     def get_revs(self):
@@ -68,7 +68,7 @@ class GitRepo(object):
         """Determines the head of a local repo.
         """
 
-        if not self.local:
+        if not self.local():
             return
 
         path = os.path.join(self.gitpath, "HEAD")
diff --git a/git_remote_helpers/helper.py b/git_remote_helpers/helper.py
index 56ed1dad5b..20a97b1d96 100644
--- a/git_remote_helpers/helper.py
+++ b/git_remote_helpers/helper.py
@@ -71,7 +71,7 @@ class RemoteHelper(object):
         """Updates (or clones) a local repo.
         """
 
-        if repo.local:
+        if repo.local():
             return repo
 
         path = repo.non_local.clone(repo.gitdir)
@@ -130,7 +130,7 @@ class RemoteHelper(object):
 
             changed[name] = value
 
-        if not repo.local:
+        if not repo.local():
             repo.non_local.push(repo.gitdir)
 
         for ref in changed:

From 6a0b2fd46823ee891bc6409af85aa84dd42ef68c Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 22 Aug 2010 01:22:14 -0500
Subject: [PATCH 3702/3720] git_remote_helpers: add fastimport library

---
 git_remote_helpers/fastimport/__init__.py     |   0
 git_remote_helpers/fastimport/commands.py     | 469 +++++++++++++
 git_remote_helpers/fastimport/dates.py        |  79 +++
 git_remote_helpers/fastimport/errors.py       | 182 +++++
 git_remote_helpers/fastimport/head_tracker.py |  47 ++
 git_remote_helpers/fastimport/helpers.py      |  88 +++
 git_remote_helpers/fastimport/idmapfile.py    |  65 ++
 git_remote_helpers/fastimport/parser.py       | 621 ++++++++++++++++++
 git_remote_helpers/fastimport/processor.py    | 222 +++++++
 git_remote_helpers/setup.py                   |   3 +-
 10 files changed, 1775 insertions(+), 1 deletion(-)
 create mode 100644 git_remote_helpers/fastimport/__init__.py
 create mode 100644 git_remote_helpers/fastimport/commands.py
 create mode 100644 git_remote_helpers/fastimport/dates.py
 create mode 100644 git_remote_helpers/fastimport/errors.py
 create mode 100644 git_remote_helpers/fastimport/head_tracker.py
 create mode 100644 git_remote_helpers/fastimport/helpers.py
 create mode 100644 git_remote_helpers/fastimport/idmapfile.py
 create mode 100644 git_remote_helpers/fastimport/parser.py
 create mode 100644 git_remote_helpers/fastimport/processor.py

diff --git a/git_remote_helpers/fastimport/__init__.py b/git_remote_helpers/fastimport/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/git_remote_helpers/fastimport/commands.py b/git_remote_helpers/fastimport/commands.py
new file mode 100644
index 0000000000..b3c86c4910
--- /dev/null
+++ b/git_remote_helpers/fastimport/commands.py
@@ -0,0 +1,469 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Import command classes."""
+
+import os
+
+# There is a bug in git 1.5.4.3 and older by which unquoting a string consumes
+# one extra character. Set this variable to True to work-around it. It only
+# happens when renaming a file whose name contains spaces and/or quotes, and
+# the symptom is:
+#   % git-fast-import
+#   fatal: Missing space after source: R "file 1.txt" file 2.txt
+# http://git.kernel.org/?p=git/git.git;a=commit;h=c8744d6a8b27115503565041566d97c21e722584
+GIT_FAST_IMPORT_NEEDS_EXTRA_SPACE_AFTER_QUOTE = False
+
+
+# Lists of command names
+COMMAND_NAMES = ['blob', 'checkpoint', 'commit', 'feature', 'progress',
+    'reset', 'tag']
+FILE_COMMAND_NAMES = ['filemodify', 'filedelete', 'filecopy', 'filerename',
+    'filedeleteall']
+
+
+# Feature names
+MULTIPLE_AUTHORS_FEATURE = "multiple-authors"
+COMMIT_PROPERTIES_FEATURE = "commit-properties"
+EMPTY_DIRS_FEATURE = "empty-directories"
+FEATURE_NAMES = [
+    MULTIPLE_AUTHORS_FEATURE,
+    COMMIT_PROPERTIES_FEATURE,
+    EMPTY_DIRS_FEATURE,
+    ]
+
+
+# for classes with no meaningful __str__()
+def _simplerepr(self):
+    return "<%s at 0x%x>" % (self.__class__.__name__, id(self))
+
+# classes that define __str__() should use this instead
+def _detailrepr(self):
+    return ("<%s at 0x%x: %s>"
+            % (self.__class__.__name__, id(self), str(self)))
+
+
+class ImportCommand(object):
+    """Base class for import commands."""
+
+    def __init__(self, name):
+        self.name = name
+        # List of field names not to display
+        self._binary = []
+
+    __repr__ = _simplerepr
+
+    def format(self):
+        """Format this command as a fastimport dump fragment.
+
+        Returns a (possibly multiline) string that, if seen in a
+        fastimport stream, would parse to an equivalent command object.
+        """
+        raise NotImplementedError("abstract method")
+
+    def dump_str(self, names=None, child_lists=None, verbose=False):
+        """Dump fields as a string.
+
+        :param names: the list of fields to include or
+            None for all public fields
+        :param child_lists: dictionary of child command names to
+            fields for that child command to include
+        :param verbose: if True, prefix each line with the command class and
+            display fields as a dictionary; if False, dump just the field
+            values with tabs between them
+        """
+        interesting = {}
+        if names is None:
+            fields = [k for k in self.__dict__.keys() if not k.startswith('_')]
+        else:
+            fields = names
+        for field in fields:
+            value = self.__dict__.get(field)
+            if field in self._binary and value is not None:
+                value = '(...)'
+            interesting[field] = value
+        if verbose:
+            return "%s: %s" % (self.__class__.__name__, interesting)
+        else:
+            return "\t".join([repr(interesting[k]) for k in fields])
+
+
+class _MarkMixin(object):
+    """mixin for fastimport commands with a mark: blob, commit."""
+    def __init__(self, mark, location):
+        self.mark= mark
+        self.location = location
+
+        # Provide a unique id in case the mark is missing
+        if mark is None:
+            self.id = '%s@%d' % (os.path.basename(location[0]), location[1])
+        else:
+            self.id = ':%s' % mark
+
+    def __str__(self):
+        return self.id
+
+    __repr__ = _detailrepr
+
+
+class BlobCommand(ImportCommand, _MarkMixin):
+
+    def __init__(self, mark, data, location):
+        ImportCommand.__init__(self, 'blob')
+        _MarkMixin.__init__(self, mark, location)
+        self.data = data
+        self._binary = ['data']
+
+    def format(self):
+        if self.mark is None:
+            mark_line = ""
+        else:
+            mark_line = "\nmark :%s" % self.mark
+        return "blob%s\ndata %d\n%s" % (mark_line, len(self.data), self.data)
+
+
+class CheckpointCommand(ImportCommand):
+
+    def __init__(self):
+        ImportCommand.__init__(self, 'checkpoint')
+
+    def format(self):
+        return "checkpoint"
+
+
+class CommitCommand(ImportCommand, _MarkMixin):
+
+    def __init__(self, ref, mark, author, committer, message, from_,
+        merges, file_cmds, location=None, more_authors=None, properties=None):
+        ImportCommand.__init__(self, 'commit')
+        _MarkMixin.__init__(self, mark, location)
+        self.ref = ref
+        self.author = author
+        self.committer = committer
+        self.message = message
+        self.from_ = from_
+        self.merges = merges
+        self.file_cmds = file_cmds
+        self.more_authors = more_authors
+        self.properties = properties
+        self._binary = ['file_cmds']
+
+    def format(self, use_features=True, include_file_contents=True):
+        if self.mark is None:
+            mark_line = ""
+        else:
+            mark_line = "\nmark :%s" % self.mark
+        if self.author is None:
+            author_section = ""
+        else:
+            author_section = "\nauthor %s" % format_who_when(self.author)
+            if use_features and self.more_authors:
+                for author in self.more_authors:
+                    author_section += "\nauthor %s" % format_who_when(author)
+        committer = "committer %s" % format_who_when(self.committer)
+        if self.message is None:
+            msg_section = ""
+        else:
+            msg = self.message.encode('utf8')
+            msg_section = "\ndata %d\n%s" % (len(msg), msg)
+        if self.from_ is None:
+            from_line = ""
+        else:
+            from_line = "\nfrom %s" % self.from_
+        if self.merges is None:
+            merge_lines = ""
+        else:
+            merge_lines = "".join(["\nmerge %s" % (m,)
+                for m in self.merges])
+        if use_features and self.properties:
+            property_lines = []
+            for name in sorted(self.properties):
+                value = self.properties[name]
+                property_lines.append("\n" + format_property(name, value))
+            properties_section = "".join(property_lines)
+        else:
+            properties_section = ""
+        if self.file_cmds is None:
+            filecommands = ""
+        else:
+            if include_file_contents:
+                format_str = "\n%r"
+            else:
+                format_str = "\n%s"
+            filecommands = "".join(
+                ["\n" + fc.format() for fc in self.file_cmds])
+        return "commit %s%s%s\n%s%s%s%s%s%s" % (self.ref, mark_line,
+            author_section, committer, msg_section, from_line, merge_lines,
+            properties_section, filecommands)
+
+    def dump_str(self, names=None, child_lists=None, verbose=False):
+        result = [ImportCommand.dump_str(self, names, verbose=verbose)]
+        for f in self.file_cmds:
+            if child_lists is None:
+                continue
+            try:
+                child_names = child_lists[f.name]
+            except KeyError:
+                continue
+            result.append("\t%s" % f.dump_str(child_names, verbose=verbose))
+        return '\n'.join(result)
+
+
+class FeatureCommand(ImportCommand):
+
+    def __init__(self, feature_name, value=None, location=None):
+        ImportCommand.__init__(self, 'feature')
+        self.feature_name = feature_name
+        self.value = value
+        self.location = location
+
+    def format(self):
+        if self.value is None:
+            value_text = ""
+        else:
+            value_text = "=%s" % self.value
+        return "feature %s%s" % (self.feature_name, value_text)
+
+
+class ProgressCommand(ImportCommand):
+
+    def __init__(self, message):
+        ImportCommand.__init__(self, 'progress')
+        self.message = message
+
+    def format(self):
+        return "progress %s" % (self.message,)
+
+
+class ResetCommand(ImportCommand):
+
+    def __init__(self, ref, from_):
+        ImportCommand.__init__(self, 'reset')
+        self.ref = ref
+        self.from_ = from_
+
+    def format(self):
+        if self.from_ is None:
+            from_line = ""
+        else:
+            # According to git-fast-import(1), the extra LF is optional here;
+            # however, versions of git up to 1.5.4.3 had a bug by which the LF
+            # was needed. Always emit it, since it doesn't hurt and maintains
+            # compatibility with older versions.
+            # http://git.kernel.org/?p=git/git.git;a=commit;h=655e8515f279c01f525745d443f509f97cd805ab
+            from_line = "\nfrom %s\n" % self.from_
+        return "reset %s%s" % (self.ref, from_line)
+
+
+class TagCommand(ImportCommand):
+
+    def __init__(self, id, from_, tagger, message):
+        ImportCommand.__init__(self, 'tag')
+        self.id = id
+        self.from_ = from_
+        self.tagger = tagger
+        self.message = message
+
+    def __str__(self):
+        return self.id
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        if self.from_ is None:
+            from_line = ""
+        else:
+            from_line = "\nfrom %s" % self.from_
+        if self.tagger is None:
+            tagger_line = ""
+        else:
+            tagger_line = "\ntagger %s" % format_who_when(self.tagger)
+        if self.message is None:
+            msg_section = ""
+        else:
+            msg = self.message.encode('utf8')
+            msg_section = "\ndata %d\n%s" % (len(msg), msg)
+        return "tag %s%s%s%s" % (self.id, from_line, tagger_line, msg_section)
+
+
+class FileCommand(ImportCommand):
+    """Base class for file commands."""
+    pass
+
+
+class FileModifyCommand(FileCommand):
+
+    def __init__(self, path, mode, dataref, data):
+        # Either dataref or data should be null
+        FileCommand.__init__(self, 'filemodify')
+        self.path = check_path(path)
+        self.mode = mode
+        self.dataref = dataref
+        self.data = data
+        self._binary = ['data']
+
+    def __str__(self):
+        return self.path
+
+    __repr__ = _detailrepr
+
+    def format(self, include_file_contents=True):
+        datastr = ""
+        if self.dataref is None:
+            dataref = "inline"
+            if include_file_contents:
+                datastr = "\ndata %d\n%s" % (len(self.data), self.data)
+        else:
+            dataref = "%s" % (self.dataref,)
+        path = format_path(self.path)
+        return "M %s %s %s%s" % (self.mode, dataref, path, datastr)
+
+    def is_regular(self):
+        """Return true if this is a regular file (mode 644)."""
+        return self.mode.endswith("644")
+
+    def is_executable(self):
+        """Return true if this is an executable file (mode 755)."""
+        return self.mode.endswith("755")
+
+    def is_symlink(self):
+        """Return true if this is a symlink (mode 120000)."""
+        return self.mode == "120000"
+
+    def is_gitlink(self):
+        """Return true if this is a gitlink (mode 160000)."""
+        return self.mode == "160000"
+
+
+class FileDeleteCommand(FileCommand):
+
+    def __init__(self, path):
+        FileCommand.__init__(self, 'filedelete')
+        self.path = check_path(path)
+
+    def __str__(self):
+        return self.path
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "D %s" % (format_path(self.path),)
+
+
+class FileCopyCommand(FileCommand):
+
+    def __init__(self, src_path, dest_path):
+        FileCommand.__init__(self, 'filecopy')
+        self.src_path = check_path(src_path)
+        self.dest_path = check_path(dest_path)
+
+    def __str__(self):
+        return "%s -> %s" % (self.src_path, self.dest_path)
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "C %s %s" % (
+            format_path(self.src_path, quote_spaces=True),
+            format_path(self.dest_path))
+
+
+class FileRenameCommand(FileCommand):
+
+    def __init__(self, old_path, new_path):
+        FileCommand.__init__(self, 'filerename')
+        self.old_path = check_path(old_path)
+        self.new_path = check_path(new_path)
+
+    def __str__(self):
+        return "%s -> %s" % (self.old_path, self.new_path)
+
+    __repr__ = _detailrepr
+
+    def format(self):
+        return "R %s %s" % (
+            format_path(self.old_path, quote_spaces=True),
+            format_path(self.new_path))
+
+
+class FileDeleteAllCommand(FileCommand):
+
+    def __init__(self):
+        FileCommand.__init__(self, 'filedeleteall')
+
+    def format(self):
+        return "deleteall"
+
+
+def check_path(path):
+    """Check that a path is legal.
+
+    :return: the path if all is OK
+    :raise ValueError: if the path is illegal
+    """
+    if path is None or path == '':
+        raise ValueError("illegal path '%s'" % path)
+    return path
+
+
+def format_path(p, quote_spaces=False):
+    """Format a path in utf8, quoting it if necessary."""
+    if '\n' in p:
+        import re
+        p = re.sub('\n', '\\n', p)
+        quote = True
+    else:
+        quote = p[0] == '"' or (quote_spaces and ' ' in p)
+    if quote:
+        extra = GIT_FAST_IMPORT_NEEDS_EXTRA_SPACE_AFTER_QUOTE and ' ' or ''
+        p = '"%s"%s' % (p, extra)
+    return p.encode('utf8')
+
+
+def format_who_when(fields):
+    """Format a tuple of name,email,secs-since-epoch,utc-offset-secs as a string."""
+    offset = fields[3]
+    if offset < 0:
+        offset_sign = '-'
+        offset = abs(offset)
+    else:
+        offset_sign = '+'
+    offset_hours = offset / 3600
+    offset_minutes = offset / 60 - offset_hours * 60
+    offset_str = "%s%02d%02d" % (offset_sign, offset_hours, offset_minutes)
+    name = fields[0]
+    if name == '':
+        sep = ''
+    else:
+        sep = ' '
+    if isinstance(name, unicode):
+        name = name.encode('utf8')
+    email = fields[1]
+    if isinstance(email, unicode):
+        email = email.encode('utf8')
+    result = "%s%s<%s> %d %s" % (name, sep, email, fields[2], offset_str)
+    return result
+
+
+def format_property(name, value):
+    """Format the name and value (both unicode) of a property as a string."""
+    utf8_name = name.encode('utf8')
+    if value is not None:
+        utf8_value = value.encode('utf8')
+        result = "property %s %d %s" % (utf8_name, len(utf8_value), utf8_value)
+    else:
+        result = "property %s" % (utf8_name,)
+    return result
diff --git a/git_remote_helpers/fastimport/dates.py b/git_remote_helpers/fastimport/dates.py
new file mode 100644
index 0000000000..f532b2e249
--- /dev/null
+++ b/git_remote_helpers/fastimport/dates.py
@@ -0,0 +1,79 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Date parsing routines.
+
+Each routine returns timestamp,timezone where
+
+* timestamp is seconds since epoch
+* timezone is the offset from UTC in seconds.
+"""
+
+
+import time
+
+from git_remote_helpers.fastimport import errors
+
+
+def parse_raw(s, lineno=0):
+    """Parse a date from a raw string.
+    
+    The format must be exactly "seconds-since-epoch offset-utc".
+    See the spec for details.
+    """
+    timestamp_str, timezone_str = s.split(' ', 1)
+    timestamp = float(timestamp_str)
+    timezone = _parse_tz(timezone_str, lineno)
+    return timestamp, timezone
+
+
+def _parse_tz(tz, lineno):
+    """Parse a timezone specification in the [+|-]HHMM format.
+
+    :return: the timezone offset in seconds.
+    """
+    # from git_repository.py in bzr-git
+    if len(tz) != 5:
+        raise errors.InvalidTimezone(lineno, tz)
+    sign = {'+': +1, '-': -1}[tz[0]]
+    hours = int(tz[1:3])
+    minutes = int(tz[3:])
+    return sign * 60 * (60 * hours + minutes)
+
+
+def parse_rfc2822(s, lineno=0):
+    """Parse a date from a rfc2822 string.
+    
+    See the spec for details.
+    """
+    raise NotImplementedError(parse_rfc2822)
+
+
+def parse_now(s, lineno=0):
+    """Parse a date from a string.
+
+    The format must be exactly "now".
+    See the spec for details.
+    """
+    return time.time(), 0
+
+
+# Lookup tabel of date parsing routines
+DATE_PARSERS_BY_NAME = {
+    'raw':      parse_raw,
+    'rfc2822':  parse_rfc2822,
+    'now':      parse_now,
+    }
diff --git a/git_remote_helpers/fastimport/errors.py b/git_remote_helpers/fastimport/errors.py
new file mode 100644
index 0000000000..b8cf26fd09
--- /dev/null
+++ b/git_remote_helpers/fastimport/errors.py
@@ -0,0 +1,182 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Exception classes for fastimport"""
+
+
+class FastImportError(StandardError):
+    """The base exception class for all import processing exceptions."""
+
+    _fmt = "Unknown Import Error"
+
+    def __str__(self):
+        return self._fmt % self.__dict__
+
+class ParsingError(FastImportError):
+    """The base exception class for all import processing exceptions."""
+
+    _fmt = "Unknown Import Parsing Error"
+
+    def __init__(self, filename, lineno):
+        FastImportError.__init__(self)
+        self.filename = filename
+        self.lineno = lineno
+
+    def __str__(self):
+        result = []
+        if self.filename:
+            result.append(self.filename)
+            result.append(", ")
+        result.append("line ")
+        result.append(str(self.lineno))
+        result.append(": ")
+        result.append(FastImportError.__str__(self))
+        return "".join(result)
+
+
+class MissingBytes(ParsingError):
+    """Raised when EOF encountered while expecting to find more bytes."""
+
+    _fmt = ("Unexpected EOF - expected %(expected)d bytes,"
+        " found %(found)d")
+
+    def __init__(self, filename, lineno, expected, found):
+        ParsingError.__init__(self, filename, lineno)
+        self.expected = expected
+        self.found = found
+
+
+class MissingTerminator(ParsingError):
+    """Raised when EOF encountered while expecting to find a terminator."""
+
+    _fmt = "Unexpected EOF - expected '%(terminator)s' terminator"
+
+    def __init__(self, filename, lineno, terminator):
+        ParsingError.__init__(self, filename, lineno)
+        self.terminator = terminator
+
+
+class InvalidCommand(ParsingError):
+    """Raised when an unknown command found."""
+
+    _fmt = ("Invalid command '%(cmd)s'")
+
+    def __init__(self, filename, lineno, cmd):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+
+
+class MissingSection(ParsingError):
+    """Raised when a section is required in a command but not present."""
+
+    _fmt = ("Command %(cmd)s is missing section %(section)s")
+
+    def __init__(self, filename, lineno, cmd, section):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+        self.section = section
+
+
+class BadFormat(ParsingError):
+    """Raised when a section is formatted incorrectly."""
+
+    _fmt = ("Bad format for section %(section)s in "
+            "command %(cmd)s: found '%(text)s'")
+
+    def __init__(self, filename, lineno, cmd, section, text):
+        ParsingError.__init__(self, filename, lineno)
+        self.cmd = cmd
+        self.section = section
+        self.text = text
+
+
+class InvalidTimezone(ParsingError):
+    """Raised when converting a string timezone to a seconds offset."""
+
+    _fmt = "Timezone %(timezone)r could not be converted.%(reason)s"
+
+    def __init__(self, filename, lineno, timezone, reason=None):
+        ParsingError.__init__(self, filename, lineno)
+        self.timezone = timezone
+        if reason:
+            self.reason = ' ' + reason
+        else:
+            self.reason = ''
+
+
+class UnknownDateFormat(FastImportError):
+    """Raised when an unknown date format is given."""
+
+    _fmt = ("Unknown date format '%(format)s'")
+
+    def __init__(self, format):
+        FastImportError.__init__(self)
+        self.format = format
+
+
+class MissingHandler(FastImportError):
+    """Raised when a processor can't handle a command."""
+
+    _fmt = ("Missing handler for command %(cmd)s")
+
+    def __init__(self, cmd):
+        FastImportError.__init__(self)
+        self.cmd = cmd
+
+
+class UnknownParameter(FastImportError):
+    """Raised when an unknown parameter is passed to a processor."""
+
+    _fmt = ("Unknown parameter - '%(param)s' not in %(knowns)s")
+
+    def __init__(self, param, knowns):
+        FastImportError.__init__(self)
+        self.param = param
+        self.knowns = knowns
+
+
+class BadRepositorySize(FastImportError):
+    """Raised when the repository has an incorrect number of revisions."""
+
+    _fmt = ("Bad repository size - %(found)d revisions found, "
+        "%(expected)d expected")
+
+    def __init__(self, expected, found):
+        FastImportError.__init__(self)
+        self.expected = expected
+        self.found = found
+
+
+class BadRestart(FastImportError):
+    """Raised when the import stream and id-map do not match up."""
+
+    _fmt = ("Bad restart - attempted to skip commit %(commit_id)s "
+        "but matching revision-id is unknown")
+
+    def __init__(self, commit_id):
+        FastImportError.__init__(self)
+        self.commit_id = commit_id
+
+
+class UnknownFeature(FastImportError):
+    """Raised when an unknown feature is given in the input stream."""
+
+    _fmt = ("Unknown feature '%(feature)s' - try a later importer or "
+        "an earlier data format")
+
+    def __init__(self, feature):
+        FastImportError.__init__(self)
+        self.feature = feature
diff --git a/git_remote_helpers/fastimport/head_tracker.py b/git_remote_helpers/fastimport/head_tracker.py
new file mode 100644
index 0000000000..ad6b48c8b8
--- /dev/null
+++ b/git_remote_helpers/fastimport/head_tracker.py
@@ -0,0 +1,47 @@
+
+
+class HeadTracker(object):
+    """
+    Keep track of the heads in a fastimport stream.
+    """
+    def __init__(self):
+        self.last_ref = None
+
+        # map git ref name (e.g. "refs/heads/master") to id of last
+        # commit with that ref
+        self.last_ids = {}
+
+        # the set of heads seen so far in the stream, as a mapping
+        # from commit id of the head to set of ref names
+        self.heads = {}
+
+    def track_heads(self, cmd):
+        """Track the repository heads given a CommitCommand.
+        
+        :param cmd: the CommitCommand
+        :return: the list of parents in terms of commit-ids
+        """
+        # Get the true set of parents
+        if cmd.from_ is not None:
+            parents = [cmd.from_]
+        else:
+            last_id = self.last_ids.get(cmd.ref)
+            if last_id is not None:
+                parents = [last_id]
+            else:
+                parents = []
+        parents.extend(cmd.merges)
+
+        # Track the heads
+        self.track_heads_for_ref(cmd.ref, cmd.id, parents)
+        return parents
+
+    def track_heads_for_ref(self, cmd_ref, cmd_id, parents=None):
+        if parents is not None:
+            for parent in parents:
+                if parent in self.heads:
+                    del self.heads[parent]
+        self.heads.setdefault(cmd_id, set()).add(cmd_ref)
+        self.last_ids[cmd_ref] = cmd_id
+        self.last_ref = cmd_ref
+    
diff --git a/git_remote_helpers/fastimport/helpers.py b/git_remote_helpers/fastimport/helpers.py
new file mode 100644
index 0000000000..3ce5a98e17
--- /dev/null
+++ b/git_remote_helpers/fastimport/helpers.py
@@ -0,0 +1,88 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Miscellaneous useful stuff."""
+
+import os
+
+def single_plural(n, single, plural):
+    """Return a single or plural form of a noun based on number."""
+    if n == 1:
+        return single
+    else:
+        return plural
+
+
+def invert_dict(d):
+    """Invert a dictionary with keys matching each value turned into a list."""
+    # Based on recipe from ASPN
+    result = {}
+    for k, v in d.iteritems():
+        keys = result.setdefault(v, [])
+        keys.append(k)
+    return result
+
+
+def invert_dictset(d):
+    """Invert a dictionary with keys matching a set of values, turned into lists."""
+    # Based on recipe from ASPN
+    result = {}
+    for k, c in d.iteritems():
+        for v in c:
+            keys = result.setdefault(v, [])
+            keys.append(k)
+    return result
+
+
+def _common_path_and_rest(l1, l2, common=[]):
+    # From http://code.activestate.com/recipes/208993/
+    if len(l1) < 1: return (common, l1, l2)
+    if len(l2) < 1: return (common, l1, l2)
+    if l1[0] != l2[0]: return (common, l1, l2)
+    return _common_path_and_rest(l1[1:], l2[1:], common+[l1[0]])
+
+
+def common_path(path1, path2):
+    """Find the common bit of 2 paths."""
+    return ''.join(_common_path_and_rest(path1, path2)[0])
+
+
+def common_directory(paths):
+    """Find the deepest common directory of a list of paths.
+    
+    :return: if no paths are provided, None is returned;
+      if there is no common directory, '' is returned;
+      otherwise the common directory with a trailing / is returned.
+    """
+    def get_dir_with_slash(path):
+        if path == '' or path.endswith('/'):
+            return path
+        else:
+            dirname, basename = os.path.split(path)
+            if dirname == '':
+                return dirname
+            else:
+                return dirname + '/'
+
+    if not paths:
+        return None
+    elif len(paths) == 1:
+        return get_dir_with_slash(paths[0])
+    else:
+        common = common_path(paths[0], paths[1])
+        for path in paths[2:]:
+            common = common_path(common, path)
+        return get_dir_with_slash(common)
diff --git a/git_remote_helpers/fastimport/idmapfile.py b/git_remote_helpers/fastimport/idmapfile.py
new file mode 100644
index 0000000000..7b4ccf4afe
--- /dev/null
+++ b/git_remote_helpers/fastimport/idmapfile.py
@@ -0,0 +1,65 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Routines for saving and loading the id-map file."""
+
+import os
+
+
+def save_id_map(filename, revision_ids):
+    """Save the mapping of commit ids to revision ids to a file.
+
+    Throws the usual exceptions if the file cannot be opened,
+    written to or closed.
+
+    :param filename: name of the file to save the data to
+    :param revision_ids: a dictionary of commit ids to revision ids.
+    """
+    f = open(filename, 'wb')
+    try:
+        for commit_id, rev_id in revision_ids.iteritems():
+            f.write("%s %s\n" % (commit_id, rev_id))
+        f.flush()
+    finally:
+        f.close()
+
+
+def load_id_map(filename):
+    """Load the mapping of commit ids to revision ids from a file.
+
+    If the file does not exist, an empty result is returned.
+    If the file does exists but cannot be opened, read or closed,
+    the normal exceptions are thrown.
+
+    NOTE: It is assumed that commit-ids do not have embedded spaces.
+
+    :param filename: name of the file to save the data to
+    :result: map, count where:
+      map = a dictionary of commit ids to revision ids;
+      count = the number of keys in map
+    """
+    result = {}
+    count = 0
+    if os.path.exists(filename):
+        f = open(filename)
+        try:
+            for line in f:
+                parts = line[:-1].split(' ', 1)
+                result[parts[0]] = parts[1]
+                count += 1
+        finally:
+            f.close()
+    return result, count
diff --git a/git_remote_helpers/fastimport/parser.py b/git_remote_helpers/fastimport/parser.py
new file mode 100644
index 0000000000..f9c2655913
--- /dev/null
+++ b/git_remote_helpers/fastimport/parser.py
@@ -0,0 +1,621 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import warnings
+
+"""Parser of import data into command objects.
+
+In order to reuse existing front-ends, the stream format is a subset of
+the one used by git-fast-import (as of the 1.5.4 release of git at least).
+The grammar is:
+
+  stream ::= cmd*;
+
+  cmd ::= new_blob
+        | new_commit
+        | new_tag
+        | reset_branch
+        | checkpoint
+        | progress
+        ;
+
+  new_blob ::= 'blob' lf
+    mark?
+    file_content;
+  file_content ::= data;
+
+  new_commit ::= 'commit' sp ref_str lf
+    mark?
+    ('author' sp name '<' email '>' when lf)?
+    'committer' sp name '<' email '>' when lf
+    commit_msg
+    ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
+    ('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
+    file_change*
+    lf?;
+  commit_msg ::= data;
+
+  file_change ::= file_clr
+    | file_del
+    | file_rnm
+    | file_cpy
+    | file_obm
+    | file_inm;
+  file_clr ::= 'deleteall' lf;
+  file_del ::= 'D' sp path_str lf;
+  file_rnm ::= 'R' sp path_str sp path_str lf;
+  file_cpy ::= 'C' sp path_str sp path_str lf;
+  file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
+  file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
+    data;
+
+  new_tag ::= 'tag' sp tag_str lf
+    'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
+    'tagger' sp name '<' email '>' when lf
+    tag_msg;
+  tag_msg ::= data;
+
+  reset_branch ::= 'reset' sp ref_str lf
+    ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
+    lf?;
+
+  checkpoint ::= 'checkpoint' lf
+    lf?;
+
+  progress ::= 'progress' sp not_lf* lf
+    lf?;
+
+     # note: the first idnum in a stream should be 1 and subsequent
+     # idnums should not have gaps between values as this will cause
+     # the stream parser to reserve space for the gapped values.  An
+     # idnum can be updated in the future to a new object by issuing
+     # a new mark directive with the old idnum.
+     #
+  mark ::= 'mark' sp idnum lf;
+  data ::= (delimited_data | exact_data)
+    lf?;
+
+    # note: delim may be any string but must not contain lf.
+    # data_line may contain any data but must not be exactly
+    # delim. The lf after the final data_line is included in
+    # the data.
+  delimited_data ::= 'data' sp '<<' delim lf
+    (data_line lf)*
+    delim lf;
+
+     # note: declen indicates the length of binary_data in bytes.
+     # declen does not include the lf preceeding the binary data.
+     #
+  exact_data ::= 'data' sp declen lf
+    binary_data;
+
+     # note: quoted strings are C-style quoting supporting \c for
+     # common escapes of 'c' (e..g \n, \t, \\, \") or \nnn where nnn
+     # is the signed byte value in octal.  Note that the only
+     # characters which must actually be escaped to protect the
+     # stream formatting is: \, \" and LF.  Otherwise these values
+     # are UTF8.
+     #
+  ref_str     ::= ref;
+  sha1exp_str ::= sha1exp;
+  tag_str     ::= tag;
+  path_str    ::= path    | '"' quoted(path)    '"' ;
+  mode        ::= '100644' | '644'
+                | '100755' | '755'
+                | '120000'
+                ;
+
+  declen ::= # unsigned 32 bit value, ascii base10 notation;
+  bigint ::= # unsigned integer value, ascii base10 notation;
+  binary_data ::= # file content, not interpreted;
+
+  when         ::= raw_when | rfc2822_when;
+  raw_when     ::= ts sp tz;
+  rfc2822_when ::= # Valid RFC 2822 date and time;
+
+  sp ::= # ASCII space character;
+  lf ::= # ASCII newline (LF) character;
+
+     # note: a colon (':') must precede the numerical value assigned to
+     # an idnum.  This is to distinguish it from a ref or tag name as
+     # GIT does not permit ':' in ref or tag strings.
+     #
+  idnum   ::= ':' bigint;
+  path    ::= # GIT style file path, e.g. \"a/b/c\";
+  ref     ::= # GIT ref name, e.g. \"refs/heads/MOZ_GECKO_EXPERIMENT\";
+  tag     ::= # GIT tag name, e.g. \"FIREFOX_1_5\";
+  sha1exp ::= # Any valid GIT SHA1 expression;
+  hexsha1 ::= # SHA1 in hexadecimal format;
+
+     # note: name and email are UTF8 strings, however name must not
+     # contain '<' or lf and email must not contain any of the
+     # following: '<', '>', lf.
+     #
+  name  ::= # valid GIT author/committer name;
+  email ::= # valid GIT author/committer email;
+  ts    ::= # time since the epoch in seconds, ascii base10 notation;
+  tz    ::= # GIT style timezone;
+
+     # note: comments may appear anywhere in the input, except
+     # within a data command.  Any form of the data command
+     # always escapes the related input from comment processing.
+     #
+     # In case it is not clear, the '#' that starts the comment
+     # must be the first character on that the line (an lf have
+     # preceeded it).
+     #
+  comment ::= '#' not_lf* lf;
+  not_lf  ::= # Any byte that is not ASCII newline (LF);
+"""
+
+
+import re
+import sys
+
+from git_remote_helpers.fastimport import (
+    commands,
+    dates,
+    errors
+    )
+
+
+## Stream parsing ##
+
+class LineBasedParser(object):
+
+    def __init__(self, input, filename=None):
+        """A Parser that keeps track of line numbers.
+
+        :param input: the file-like object to read from
+        """
+        self.input = input
+        if filename is None:
+            try:
+                self.filename = input.name
+            except AttributeError:
+                self.filename = "(unknown)"
+        else:
+            self.filename = filename
+        self.lineno = 0
+        # Lines pushed back onto the input stream
+        self._buffer = []
+
+    def abort(self, exception, *args):
+        """Raise an exception providing line number information."""
+        raise exception(self.filename, self.lineno, *args)
+
+    def readline(self):
+        """Get the next line including the newline or '' on EOF."""
+        self.lineno += 1
+        if self._buffer:
+            return self._buffer.pop()
+        else:
+            return self.input.readline()
+
+    def next_line(self):
+        """Get the next line without the newline or None on EOF."""
+        line = self.readline()
+        if line:
+            return line[:-1]
+        else:
+            return None
+
+    def push_line(self, line):
+        """Push line back onto the line buffer.
+        
+        :param line: the line with no trailing newline
+        """
+        self.lineno -= 1
+        self._buffer.append(line + "\n")
+
+    def read_bytes(self, count):
+        """Read a given number of bytes from the input stream.
+        
+        Throws MissingBytes if the bytes are not found.
+
+        Note: This method does not read from the line buffer.
+
+        :return: a string
+        """
+        result = self.input.read(count)
+        found = len(result)
+        self.lineno += result.count("\n")
+        if found != count:
+            self.abort(errors.MissingBytes, count, found)
+        return result
+
+    def read_until(self, terminator):
+        """Read the input stream until the terminator is found.
+        
+        Throws MissingTerminator if the terminator is not found.
+
+        Note: This method does not read from the line buffer.
+
+        :return: the bytes read up to but excluding the terminator.
+        """
+        
+        lines = []
+        term = terminator + '\n'
+        while True:
+            line = self.input.readline()
+            if line == term:
+                break
+            else:
+                lines.append(line)
+        return ''.join(lines)
+
+
+# Regular expression used for parsing. (Note: The spec states that the name
+# part should be non-empty but git-fast-export doesn't always do that so
+# the first bit is \w*, not \w+.) Also git-fast-import code says the
+# space before the email is optional.
+_WHO_AND_WHEN_RE = re.compile(r'([^<]*)<(.*)> (.+)')
+_WHO_RE = re.compile(r'([^<]*)<(.*)>')
+
+
+class ImportParser(LineBasedParser):
+
+    def __init__(self, input, filename=None):
+        """A Parser of import commands.
+
+        :param input: the file-like object to read from
+        :param verbose: display extra information of not
+        """
+        LineBasedParser.__init__(self, input, filename)
+
+        # We auto-detect the date format when a date is first encountered
+        self.date_parser = None
+
+    def warning(self, msg):
+        sys.stderr.write("warning line %d: %s\n" % (self.lineno, msg))
+
+    def parse(self):
+        """Parse the input stream, yielding a sequence of ImportCommand
+        objects.  Iteration terminates on EOF.  Raises InvalidCommand on
+        parse error."""
+        while True:
+            line = self.next_line()
+            if line is None:
+                break
+            elif len(line) == 0 or line.startswith('#'):
+                continue
+            # Search for commands in order of likelihood
+            elif line.startswith('commit '):
+                yield self._parse_commit(line[len('commit '):])
+            elif line.startswith('blob'):
+                yield self._parse_blob()
+            elif line.startswith('done'):
+                break
+            elif line.startswith('progress '):
+                yield commands.ProgressCommand(line[len('progress '):])
+            elif line.startswith('reset '):
+                yield self._parse_reset(line[len('reset '):])
+            elif line.startswith('tag '):
+                yield self._parse_tag(line[len('tag '):])
+            elif line.startswith('checkpoint'):
+                yield commands.CheckpointCommand()
+            elif line.startswith('feature'):
+                yield self._parse_feature(line[len('feature '):])
+            else:
+                self.abort(errors.InvalidCommand, line)
+
+    def iter_commands(self):
+        warnings.warn("iter_commands() deprecated: use parse()",
+                      DeprecationWarning, stacklevel=2)
+        return self.parse()
+
+    def iter_file_commands(self):
+        """Iterator returning FileCommand objects.
+        
+        If an invalid file command is found, the line is silently
+        pushed back and iteration ends.
+        """
+        while True:
+            line = self.next_line()
+            if line is None:
+                break
+            elif len(line) == 0 or line.startswith('#'):
+                continue
+            # Search for file commands in order of likelihood
+            elif line.startswith('M '):
+                yield self._parse_file_modify(line[2:])
+            elif line.startswith('D '):
+                path = self._path(line[2:])
+                yield commands.FileDeleteCommand(path)
+            elif line.startswith('R '):
+                old, new = self._path_pair(line[2:])
+                yield commands.FileRenameCommand(old, new)
+            elif line.startswith('C '):
+                src, dest = self._path_pair(line[2:])
+                yield commands.FileCopyCommand(src, dest)
+            elif line.startswith('deleteall'):
+                yield commands.FileDeleteAllCommand()
+            else:
+                self.push_line(line)
+                break
+
+    def _parse_blob(self):
+        """Parse a blob command."""
+        location = (self.filename, self.lineno)
+        mark = self._get_mark_if_any()
+        data = self._get_data('blob')
+        return commands.BlobCommand(mark, data, location)
+
+    def _parse_commit(self, ref):
+        """Parse a commit command."""
+        location = (self.filename, self.lineno)
+        mark = self._get_mark_if_any()
+        author = self._get_user_info('commit', 'author', False)
+        more_authors = []
+        while True:
+            another_author = self._get_user_info('commit', 'author', False)
+            if another_author is not None:
+                more_authors.append(another_author)
+            else:
+                break
+        committer = self._get_user_info('commit', 'committer')
+        message = self._get_data('commit', 'message')
+        try:
+            message = message.decode('utf_8')
+        except UnicodeDecodeError:
+            self.warning(
+                "commit message not in utf8 - replacing unknown characters")
+            message = message.decode('utf_8', 'replace')
+        from_ = self._get_from()
+        merges = []
+        while True:
+            merge = self._get_merge()
+            if merge is not None:
+                # while the spec suggests it's illegal, git-fast-export
+                # outputs multiple merges on the one line, e.g.
+                # merge :x :y :z
+                these_merges = merge.split(" ")
+                merges.extend(these_merges)
+            else:
+                break
+        properties = {}
+        while True:
+            name_value = self._get_property()
+            if name_value is not None:
+                name, value = name_value
+                properties[name] = value
+            else:
+                break
+        file_cmds = list(self.iter_file_commands())
+        return commands.CommitCommand(ref, mark, author, committer, message,
+            from_, merges, file_cmds, location,
+            more_authors=more_authors, properties=properties)
+
+    def _parse_feature(self, info):
+        """Parse a feature command."""
+        parts = info.split("=", 1)
+        name = parts[0]
+        if len(parts) > 1:
+            value = self._path(parts[1])
+        else:
+            value = None
+        location = (self.filename, self.lineno)
+        return commands.FeatureCommand(name, value, location=location)
+
+
+    def _parse_file_modify(self, info):
+        """Parse a filemodify command within a commit.
+
+        :param info: a string in the format "mode dataref path"
+          (where dataref might be the hard-coded literal 'inline').
+        """
+        params = info.split(' ', 2)
+        path = self._path(params[2])
+        mode = params[0]
+        if params[1] == 'inline':
+            dataref = None
+            data = self._get_data('filemodify')
+        else:
+            dataref = params[1]
+            data = None
+        return commands.FileModifyCommand(path, mode, dataref, data)
+
+    def _parse_reset(self, ref):
+        """Parse a reset command."""
+        from_ = self._get_from()
+        return commands.ResetCommand(ref, from_)
+
+    def _parse_tag(self, name):
+        """Parse a tag command."""
+        from_ = self._get_from('tag')
+        tagger = self._get_user_info('tag', 'tagger', accept_just_who=True)
+        message = self._get_data('tag', 'message').decode('utf_8')
+        return commands.TagCommand(name, from_, tagger, message)
+
+    def _get_mark_if_any(self):
+        """Parse a mark section."""
+        line = self.next_line()
+        if line.startswith('mark :'):
+            return line[len('mark :'):]
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_from(self, required_for=None):
+        """Parse a from section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('from '):
+            return line[len('from '):]
+        elif required_for:
+            self.abort(errors.MissingSection, required_for, 'from')
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_merge(self):
+        """Parse a merge section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('merge '):
+            return line[len('merge '):]
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_property(self):
+        """Parse a property section."""
+        line = self.next_line()
+        if line is None:
+            return None
+        elif line.startswith('property '):
+            return self._name_value(line[len('property '):])
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_user_info(self, cmd, section, required=True,
+        accept_just_who=False):
+        """Parse a user section."""
+        line = self.next_line()
+        if line.startswith(section + ' '):
+            return self._who_when(line[len(section + ' '):], cmd, section,
+                accept_just_who=accept_just_who)
+        elif required:
+            self.abort(errors.MissingSection, cmd, section)
+        else:
+            self.push_line(line)
+            return None
+
+    def _get_data(self, required_for, section='data'):
+        """Parse a data section."""
+        line = self.next_line()
+        if line.startswith('data '):
+            rest = line[len('data '):]
+            if rest.startswith('<<'):
+                return self.read_until(rest[2:])
+            else:
+                size = int(rest)
+                read_bytes = self.read_bytes(size)
+                # optional LF after data.
+                next = self.input.readline()
+                self.lineno += 1
+                if len(next) > 1 or next != "\n":
+                    self.push_line(next[:-1])
+                return read_bytes
+        else:
+            self.abort(errors.MissingSection, required_for, section)
+
+    def _who_when(self, s, cmd, section, accept_just_who=False):
+        """Parse who and when information from a string.
+        
+        :return: a tuple of (name,email,timestamp,timezone). name may be
+            the empty string if only an email address was given.
+        """
+        match = _WHO_AND_WHEN_RE.search(s)
+        if match:
+            datestr = match.group(3)
+            if self.date_parser is None:
+                # auto-detect the date format
+                if len(datestr.split(' ')) == 2:
+                    format = 'raw'
+                elif datestr == 'now':
+                    format = 'now'
+                else:
+                    format = 'rfc2822'
+                self.date_parser = dates.DATE_PARSERS_BY_NAME[format]
+            when = self.date_parser(datestr, self.lineno)
+        else:
+            match = _WHO_RE.search(s)
+            if accept_just_who and match:
+                # HACK around missing time
+                # TODO: output a warning here
+                when = dates.DATE_PARSERS_BY_NAME['now']('now')
+            else:
+                self.abort(errors.BadFormat, cmd, section, s)
+
+        # Do not attempt to decode name or email address; they are just
+        # bytes.  (Everything will work out better if they are in UTF-8,
+        # but that's not guaranteed.)
+        name = match.group(1).rstrip()
+        email = match.group(2)
+        return (name, email, when[0], when[1])
+
+    def _name_value(self, s):
+        """Parse a (name,value) tuple from 'name value-length value'."""
+        parts = s.split(' ', 2)
+        name = parts[0]
+        if len(parts) == 1:
+            value = None
+        else:
+            size = int(parts[1])
+            value = parts[2]
+            still_to_read = size - len(value)
+            if still_to_read == 1:
+                value += "\n"
+            elif still_to_read > 0:
+                read_bytes = self.read_bytes(still_to_read - 1)
+                value += "\n" + read_bytes
+            value = value.decode('utf8')
+        return (name, value)
+
+    def _path(self, s):
+        """Parse a path."""
+        if s.startswith('"'):
+            if s[-1] != '"':
+                self.abort(errors.BadFormat, '?', '?', s)
+            else:
+                return _unquote_c_string(s[1:-1])
+
+        # Do *not* decode the path to a Unicode string: filenames on
+        # Unix are just bytes.  Git and Mercurial, at least, inherit
+        # this stance.  git-fast-import(1) merely says "It is
+        # recommended that  always be encoded using UTF-8.", which
+        # is good advice ... but not something we can count on here.
+        return s
+
+    def _path_pair(self, s):
+        """Parse two paths separated by a space."""
+        # TODO: handle a space in the first path
+        if s.startswith('"'):
+            parts = s[1:].split('" ', 1)
+        else:
+            parts = s.split(' ', 1)
+        if len(parts) != 2:
+            self.abort(errors.BadFormat, '?', '?', s)
+        elif parts[1].startswith('"') and parts[1].endswith('"'):
+            parts[1] = parts[1][1:-1]
+        elif parts[1].startswith('"') or parts[1].endswith('"'):
+            self.abort(errors.BadFormat, '?', '?', s)
+        return map(_unquote_c_string, parts)
+
+    def _mode(self, s):
+        """Parse a file mode into executable and symlink flags.
+        
+        :return (is_executable, is_symlink)
+        """
+        # Note: Output from git-fast-export slightly different to spec
+        if s in ['644', '100644', '0100644']:
+            return False, False
+        elif s in ['755', '100755', '0100755']:
+            return True, False
+        elif s in ['120000', '0120000']:
+            return False, True
+        else:
+            self.abort(errors.BadFormat, 'filemodify', 'mode', s)
+
+
+def _unquote_c_string(s):
+    """replace C-style escape sequences (\n, \", etc.) with real chars."""
+    # HACK: Python strings are close enough
+    return s.decode('string_escape', 'replace')
diff --git a/git_remote_helpers/fastimport/processor.py b/git_remote_helpers/fastimport/processor.py
new file mode 100644
index 0000000000..bfb4226a46
--- /dev/null
+++ b/git_remote_helpers/fastimport/processor.py
@@ -0,0 +1,222 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Processor of import commands.
+
+This module provides core processing functionality including an abstract class
+for basing real processors on. See the processors package for examples.
+"""
+
+import sys
+import time
+import logging
+
+from git_remote_helpers.fastimport import errors
+
+log = logging.getLogger(__name__)
+
+
+class ImportProcessor(object):
+    """Base class for import processors.
+    
+    Subclasses should override the pre_*, post_* and *_handler
+    methods as appropriate.
+    """
+
+    known_params = []
+
+    def __init__(self, params=None, verbose=False, outf=None):
+        if outf is None:
+            self.outf = sys.stdout
+        else:
+            self.outf = outf
+        self.verbose = verbose
+        if params is None:
+            self.params = {}
+        else:
+            self.params = params
+            self.validate_parameters()
+
+        # Handlers can set this to request exiting cleanly without
+        # iterating through the remaining commands
+        self.finished = False
+
+    def validate_parameters(self):
+        """Validate that the parameters are correctly specified."""
+        for p in self.params:
+            if p not in self.known_params:
+                raise errors.UnknownParameter(p, self.known_params)
+
+    def process(self, commands):
+        """Process a stream of fast-import commands from a parser.
+
+        :param commands: a sequence of commands.ImportCommand objects
+        """
+        self.pre_process()
+        for cmd in commands:
+            try:
+                handler = self.__class__.__dict__[cmd.name + "_handler"]
+            except KeyError:
+                raise errors.MissingHandler(cmd.name)
+            else:
+                self.pre_handler(cmd)
+                handler(self, cmd)
+                self.post_handler(cmd)
+            if self.finished:
+                break
+        self.post_process()
+
+    def pre_process(self):
+        """Hook for logic at start of processing.
+
+        Called just before process() starts iterating over its sequence
+        of commands.
+        """
+        pass
+
+    def post_process(self):
+        """Hook for logic at end of successful processing.
+
+        Called after process() finishes successfully iterating over its
+        sequence of commands (i.e. not called if an exception is raised
+        while processing commands).
+        """
+        pass
+
+    def pre_handler(self, cmd):
+        """Hook for logic before each handler starts."""
+        pass
+
+    def post_handler(self, cmd):
+        """Hook for logic after each handler finishes."""
+        pass
+
+    def progress_handler(self, cmd):
+        """Process a ProgressCommand."""
+        raise NotImplementedError(self.progress_handler)
+
+    def blob_handler(self, cmd):
+        """Process a BlobCommand."""
+        raise NotImplementedError(self.blob_handler)
+
+    def checkpoint_handler(self, cmd):
+        """Process a CheckpointCommand."""
+        raise NotImplementedError(self.checkpoint_handler)
+
+    def commit_handler(self, cmd):
+        """Process a CommitCommand."""
+        raise NotImplementedError(self.commit_handler)
+
+    def reset_handler(self, cmd):
+        """Process a ResetCommand."""
+        raise NotImplementedError(self.reset_handler)
+
+    def tag_handler(self, cmd):
+        """Process a TagCommand."""
+        raise NotImplementedError(self.tag_handler)
+
+    def feature_handler(self, cmd):
+        """Process a FeatureCommand."""
+        raise NotImplementedError(self.feature_handler)
+
+
+class CommitHandler(object):
+    """Base class for commit handling.
+    
+    Subclasses should override the pre_*, post_* and *_handler
+    methods as appropriate.
+    """
+
+    def __init__(self, command):
+        self.command = command
+
+    def process(self):
+        self.pre_process_files()
+        for fc in self.command.file_cmds:
+            try:
+                handler = self.__class__.__dict__[fc.name[4:] + "_handler"]
+            except KeyError:
+                raise errors.MissingHandler(fc.name)
+            else:
+                handler(self, fc)
+        self.post_process_files()
+
+    def _log(self, level, msg, *args):
+        log.log(level, msg + " (%s)", *(args + (self.command.id,)))
+
+    # Logging methods: unused in this library, but used by
+    # bzr-fastimport.  Could be useful for other subclasses.
+
+    def note(self, msg, *args):
+        """log.info() with context about the command"""
+        self._log(logging.INFO, msg, *args)
+
+    def warning(self, msg, *args):
+        """log.warning() with context about the command"""
+        self._log(logging.WARNING, msg, *args)
+
+    def debug(self, msg, *args):
+        """log.debug() with context about the command"""
+        self._log(logging.DEBUG, msg, *args)
+
+    def pre_process_files(self):
+        """Prepare for committing."""
+        pass
+
+    def post_process_files(self):
+        """Save the revision."""
+        pass
+
+    def modify_handler(self, filecmd):
+        """Handle a filemodify command."""
+        raise NotImplementedError(self.modify_handler)
+
+    def delete_handler(self, filecmd):
+        """Handle a filedelete command."""
+        raise NotImplementedError(self.delete_handler)
+
+    def copy_handler(self, filecmd):
+        """Handle a filecopy command."""
+        raise NotImplementedError(self.copy_handler)
+
+    def rename_handler(self, filecmd):
+        """Handle a filerename command."""
+        raise NotImplementedError(self.rename_handler)
+
+    def deleteall_handler(self, filecmd):
+        """Handle a filedeleteall command."""
+        raise NotImplementedError(self.deleteall_handler)
+
+
+def parseMany(filenames, parser_factory, processor):
+    """Parse multiple input files, sending the results all to
+    'processor'.  parser_factory must be a callable that takes one input
+    file and returns an ImportParser instance, e.g. the ImportParser
+    class object itself.  Each file in 'filenames' is opened, parsed,
+    and closed in turn.  For filename \"-\", reads stdin.
+    """
+    for filename in filenames:
+        if filename == "-":
+            infile = sys.stdin
+        else:
+            infile = open(filename, "rb")
+
+        try:
+            parser = parser_factory(infile)
+            processor.process(parser.parse())
+        finally:
+            if filename != "-":
+                infile.close()
diff --git a/git_remote_helpers/setup.py b/git_remote_helpers/setup.py
index 4d434b65cb..a19c061fdf 100644
--- a/git_remote_helpers/setup.py
+++ b/git_remote_helpers/setup.py
@@ -13,5 +13,6 @@ setup(
     author_email = 'git@vger.kernel.org',
     url = 'http://www.git-scm.com/',
     package_dir = {'git_remote_helpers': ''},
-    packages = ['git_remote_helpers', 'git_remote_helpers.git'],
+    packages = ['git_remote_helpers', 'git_remote_helpers.git',
+                'git_remote_helpers.fastimport'],
 )

From f6ae86058795296a0e60fdc89fdfe48e5d17b107 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:05:53 +0200
Subject: [PATCH 3703/3720] git-remote-hg: add hgimport, an hg-fast-import
 equivalent

This class will be used by git-remote-hg to do the heavy lifting.
---
 git_remote_helpers/hg/hgimport.py | 401 ++++++++++++++++++++++++++++++
 1 file changed, 401 insertions(+)
 create mode 100644 git_remote_helpers/hg/hgimport.py

diff --git a/git_remote_helpers/hg/hgimport.py b/git_remote_helpers/hg/hgimport.py
new file mode 100644
index 0000000000..36fee8e96b
--- /dev/null
+++ b/git_remote_helpers/hg/hgimport.py
@@ -0,0 +1,401 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Processor of import commands.
+
+This module provides core processing functionality including an abstract class
+for basing real processors on. See the processors package for examples.
+"""
+
+import os
+import shutil
+
+from mercurial import context
+from mercurial.node import nullid, hex
+
+from git_remote_helpers.util import die
+from git_remote_helpers.fastimport import processor, parser
+
+
+class commit(object):
+    def __init__(self, author, date, desc, parents, branch=None, rev=None,
+                 extra={}, sortkey=None):
+        self.author = author or 'unknown'
+        self.date = date or '0 0'
+        self.desc = desc
+        self.parents = parents
+        self.branch = branch
+        self.rev = rev
+        self.extra = extra
+        self.sortkey = sortkey
+
+
+class HgImportProcessor(processor.ImportProcessor):
+
+    def __init__(self, ui, repo):
+        super(HgImportProcessor, self).__init__()
+        self.ui = ui
+        self.repo = repo
+
+        self.branchnames = True
+
+        self.idmap = {}
+        self.commitmap = {}             # map commit ID (":1") to commit object
+        self.branchmap = {}             # map branch name to list of heads
+
+        self.tags = []                  # list of (tag, mark) tuples
+
+        self.numblobs = 0               # for progress reporting
+        self.blobdir = None
+
+    def setup(self):
+        """Setup before processing any streams."""
+        pass
+
+    def teardown(self):
+        """Cleanup after processing all streams."""
+        if self.blobdir and os.path.exists(self.blobdir):
+            self.ui.status("Removing blob dir %r ...\n" % self.blobdir)
+            shutil.rmtree(self.blobdir)
+
+    def load_marksfile(self, name):
+        try:
+            f = open(name)
+            lines = f.readlines()
+            f.close()
+            parsed = [i.strip().split(' ') for i in lines]
+            self.idmap = dict((i[0], i[1]) for i in parsed)
+        except IOError, e:
+            die("load: %s", str(e))
+
+    def write_marksfile(self, name):
+        try:
+            f = open(name, "w")
+            for pair in sorted(self.idmap.iteritems()):
+                f.write("%s %s\n" % pair)
+            f.close()
+        except IOError, e:
+            die("write: %s", str(e))
+
+    def progress_handler(self, cmd):
+        self.ui.write("Progress: %s\n" % cmd.message)
+
+    def blob_handler(self, cmd):
+        self.writeblob(cmd.id, cmd.data)
+
+    def _getblobfilename(self, blobid):
+        if self.blobdir is None:
+            raise RuntimeError("no blobs seen, so no blob directory created")
+        # XXX should escape ":" for windows
+        return os.path.join(self.blobdir, "blob-" + blobid)
+
+    def getblob(self, fileid):
+        (commitid, blobid) = fileid
+        f = open(self._getblobfilename(blobid), "rb")
+        try:
+            return f.read()
+        finally:
+            f.close()
+
+    def writeblob(self, blobid, data):
+        if self.blobdir is None:        # no blobs seen yet
+            self.blobdir = os.path.join(self.repo.root, ".hg", "blobs")
+            if not os.path.exists(self.blobdir):
+                os.mkdir(self.blobdir)
+
+        fn = self._getblobfilename(blobid)
+        blobfile = open(fn, "wb")
+        #self.ui.debug("writing blob %s to %s (%d bytes)\n"
+        #              % (blobid, fn, len(data)))
+        blobfile.write(data)
+        blobfile.close()
+
+        self.numblobs += 1
+        if self.numblobs % 500 == 0:
+            self.ui.status("%d blobs read\n" % self.numblobs)
+
+    def getmode(self, name, fileid):
+        (commitid, blobid) = fileid
+        return self.filemodes[commitid][name]
+
+    def checkpoint_handler(self, cmd):
+        # This command means nothing to us
+        pass
+
+    def _getcommit(self, committish):
+        """Given a mark reference or a branch name, return the
+        appropriate commit object.  Return None if committish is a
+        branch with no commits.  Raises KeyError if anything else is out
+        of whack.
+        """
+        if committish.startswith(":"):
+            # KeyError here indicates the input stream is broken.
+            return self.commitmap[committish]
+        else:
+            branch = self._getbranch(committish)
+            if branch is None:
+                raise ValueError("invalid committish: %r" % committish)
+
+            heads = self.branchmap.get(branch)
+            if heads is None:
+                return None
+            else:
+                # KeyError here indicates bad commit id in self.branchmap.
+                return self.commitmap[heads[-1]]
+
+    def _getbranch(self, ref):
+        """Translate a Git head ref to corresponding Mercurial branch
+        name.  E.g. \"refs/heads/foo\" is translated to \"foo\".
+        Special case: \"refs/heads/master\" becomes \"default\".  If
+        'ref' is not a head ref, return None.
+        """
+        prefix = "refs/heads/"
+        if ref.startswith(prefix):
+            branch = ref[len(prefix):]
+            if branch == "master":
+                return "default"
+            else:
+                return branch
+        else:
+            return None
+
+    def commit_handler(self, cmd):
+        # XXX this assumes the fixup branch name used by cvs2git.  In
+        # contrast, git-fast-import(1) recommends "TAG_FIXUP" (not under
+        # refs/heads), and implies that it can be called whatever the
+        # creator of the fastimport dump wants to call it.  So the name
+        # of the fixup branch should be configurable!
+        fixup = (cmd.ref == "refs/heads/TAG.FIXUP")
+
+        if cmd.from_:
+            first_parent = cmd.from_
+        else:
+            first_parent = self._getcommit(cmd.ref) # commit object
+            if first_parent is not None:
+                first_parent = first_parent.rev     # commit id
+
+        if cmd.merges:
+            if len(cmd.merges) > 1:
+                raise NotImplementedError("Can't handle more than two parents")
+            second_parent = cmd.merges[0]
+        else:
+            second_parent = None
+
+        if first_parent is None and second_parent is not None:
+            # First commit on a new branch that has 'merge' but no 'from':
+            # special case meaning branch starts with no files; the contents of
+            # the first commit (this one) determine the list of files at branch
+            # time.
+            first_parent = second_parent
+            second_parent = None
+            no_files = True             # XXX this is ignored...
+
+        self.ui.debug("commit %s: first_parent = %r, second_parent = %r\n"
+                      % (cmd, first_parent, second_parent))
+        assert ((first_parent != second_parent) or
+                (first_parent is second_parent is None)), \
+               ("commit %s: first_parent == second parent = %r"
+                % (cmd, first_parent))
+
+        # Figure out the Mercurial branch name.
+        if fixup and first_parent is not None:
+            # If this is a fixup commit, pretend it happened on the same
+            # branch as its first parent.  (We don't want a Mercurial
+            # named branch called "TAG.FIXUP" in the output repository.)
+            branch = self.commitmap[first_parent].branch
+        else:
+            branch = self._getbranch(cmd.ref)
+
+        commit_handler = HgImportCommitHandler(
+            self, cmd, self.ui)
+        commit_handler.process()
+        modified = dict(commit_handler.modified)
+        modes = commit_handler.mode
+        copies = commit_handler.copies
+
+        # in case we are converting from git or bzr, prefer author but
+        # fallback to committer (committer is required, author is
+        # optional)
+        userinfo = cmd.author or cmd.committer
+        if userinfo[0] == userinfo[1]:
+            # In order to conform to fastimport syntax, cvs2git with no
+            # authormap produces author names like "jsmith "; if
+            # we see that, revert to plain old "jsmith".
+            user = userinfo[0]
+        else:
+            user = "%s <%s>" % (userinfo[0], userinfo[1])
+
+        assert type(cmd.message) is unicode
+        text = cmd.message.encode("utf-8")
+        date = self.convert_date(userinfo)
+
+        parents = [self.idmap[i] for i in first_parent, second_parent if i]
+        cmt = commit(user, date, text, parents, branch, rev=cmd.id)
+
+        self.commitmap[cmd.id] = cmt
+        heads = self.branchmap.get(branch)
+        if heads is None:
+            heads = [cmd.id]
+        else:
+            # adding to an existing branch: replace the previous head
+            try:
+                heads.remove(first_parent)
+            except ValueError:          # first parent not a head: no problem
+                pass
+            heads.append(cmd.id)        # at end means this is tipmost
+        self.branchmap[branch] = heads
+        self.ui.debug("processed commit %s\n" % cmd)
+
+        self.idmap[cmd.id] = self.putcommit(modified, modes, copies, cmt)
+
+    def putcommit(self, files, modes, copies, commit):
+
+        def getfilectx(repo, memctx, name):
+            fileid = files[name]
+            if fileid is None:  # deleted file
+                raise IOError
+            data = self.getblob(fileid)
+            ctx = context.memfilectx(name, data, 'l' in modes,
+                                     'x' in modes, copies.get(name))
+            return ctx
+
+        parents = list(set(commit.parents))
+        nparents = len(parents)
+
+        if len(parents) < 2:
+            parents.append(nullid)
+        if len(parents) < 2:
+            parents.append(nullid)
+        p2 = parents.pop(0)
+
+        text = commit.desc
+        extra = commit.extra.copy()
+        if self.branchnames and commit.branch:
+            extra['branch'] = commit.branch
+
+        while parents:
+            p1 = p2
+            p2 = parents.pop(0)
+            ctx = context.memctx(self.repo, (p1, p2), text, files.keys(),
+                                 getfilectx, commit.author, commit.date, extra)
+            self.repo.commitctx(ctx)
+            text = "(octopus merge fixup)\n"
+            p2 = hex(self.repo.changelog.tip())
+
+        return p2
+
+    def convert_date(self, c):
+        res = (int(c[2]), int(c[3]))
+        #print c, res
+        #print type((0, 0)), type(res), len(res), type(res) is type((0, 0))
+        #if type(res) is type((0, 0)) and len(res) == 2:
+        #    print "go for it"
+        #return res
+        return "%d %d" % res
+
+    def reset_handler(self, cmd):
+        tagprefix = "refs/tags/"
+        branch = self._getbranch(cmd.ref)
+        if branch:
+            # The usual case for 'reset': (re)create the named branch.
+            # XXX what should we do if cmd.from_ is None?
+            if cmd.from_ is not None:
+                self.branchmap[branch] = [cmd.from_]
+            else:
+                # pretend the branch never existed... is this right?!?
+                try:
+                    del self.branchmap[branch]
+                except KeyError:
+                    pass
+            #else:
+            #    # XXX filename? line number?
+            #    self.ui.warn("ignoring branch reset with no 'from'\n")
+        elif cmd.ref.startswith(tagprefix):
+            # Create a "lightweight tag" in Git terms.  As I understand
+            # it, that's a tag with no description and no history --
+            # rather like CVS tags.  cvs2git turns CVS tags into Git
+            # lightweight tags, so we should make sure they become
+            # Mercurial tags.  But we don't have to fake a history for
+            # them; save them up for the end.
+            tag = cmd.ref[len(tagprefix):]
+            self.tags.append((tag, cmd.from_))
+
+    def tag_handler(self, cmd):
+        pass
+
+    def feature_handler(self, cmd):
+        if cmd.feature_name == 'done':
+            return
+        raise NotImplementedError(self.feature_handler)
+
+
+class HgImportCommitHandler(processor.CommitHandler):
+
+    def __init__(self, parent, command, ui):
+        self.parent = parent            # HgImportProcessor running the show
+        self.command = command          # CommitCommand that we're processing
+        self.ui = ui
+
+        # Files changes by this commit as a list of (filename, id)
+        # tuples where id is (commitid, blobid).  The blobid is
+        # needed to fetch the file's contents later, and the commitid
+        # is needed to fetch the mode.
+        # (XXX what about inline file contents?)
+        # (XXX how to describe deleted files?)
+        self.modified = []
+
+        # mode of files listed in self.modified: '', 'x', or 'l'
+        self.mode = {}
+
+        # dictionary of src: dest (renamed files are in here and self.modified)
+        self.copies = {}
+
+        # number of inline files seen in this commit
+        self.inlinecount = 0
+
+    def modify_handler(self, filecmd):
+        if filecmd.dataref:
+            blobid = filecmd.dataref    # blobid is the mark of the blob
+        else:
+            blobid = "%s-inline:%d" % (self.command.id, self.inlinecount)
+            assert filecmd.data is not None
+            self.parent.writeblob(blobid, filecmd.data)
+            self.inlinecount += 1
+
+        fileid = (self.command.id, blobid)
+
+        self.modified.append((filecmd.path, fileid))
+        if filecmd.mode.endswith("644"): # normal file
+            mode = ''
+        elif filecmd.mode.endswith("755"): # executable
+            mode = 'x'
+        elif filecmd.mode == "120000":  # symlink
+            mode = 'l'
+        else:
+            raise RuntimeError("mode %r unsupported" % filecmd.mode)
+
+        self.mode[filecmd.path] = mode
+
+    def delete_handler(self, filecmd):
+        self.modified.append((filecmd.path, None))
+
+    def copy_handler(self, filecmd):
+        self.copies[filecmd.src_path] = filecmd.dest_path
+
+    def rename_handler(self, filecmd):
+        # copy oldname to newname and delete oldname
+        self.copies[filecmd.oldname] = filecmd.newname
+        self.files.append((filecmd.path, None))

From 5077c76b082d86432bffadf6f1ed8446088cfc75 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:12:27 +0200
Subject: [PATCH 3704/3720] git-remote-hg: add GitHg, a helper class for
 converting hg commits to git

This class will be used by HgExport.
---
 git_remote_helpers/hg/hg.py | 116 ++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 git_remote_helpers/hg/hg.py

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
new file mode 100644
index 0000000000..758ba242d8
--- /dev/null
+++ b/git_remote_helpers/hg/hg.py
@@ -0,0 +1,116 @@
+import urllib
+import re
+
+class GitHg(object):
+    """Class that handles various aspects of converting a hg commit to git.
+    """
+
+    def __init__(self, warn):
+        """Initializes a new GitHg object with the specified warner.
+        """
+
+        self.warn = warn
+
+    def format_timezone(self, offset):
+        if offset % 60 != 0:
+            raise ValueError("Unable to handle non-minute offset.")
+        sign = (offset < 0) and '-' or '+'
+        offset = abs(offset)
+        return '%c%02d%02d' % (sign, offset / 3600, (offset / 60) % 60)
+
+    def get_committer(self, ctx):
+        extra = ctx.extra()
+
+        if 'committer' in extra:
+            # fixup timezone
+            (name_timestamp, timezone) = extra['committer'].rsplit(' ', 1)
+            try:
+                timezone = self.format_timezone(-int(timezone))
+                return '%s %s' % (name_timestamp, timezone)
+            except ValueError:
+                self.warn("Ignoring committer in extra, invalid timezone in r%s: '%s'.\n" % (ctx.rev(), timezone))
+
+        return None
+
+    def get_message(self, ctx):
+        extra = ctx.extra()
+
+        message = ctx.description() + "\n"
+        if 'message' in extra:
+            message = apply_delta(message, extra['message'])
+
+        # HG EXTRA INFORMATION
+        add_extras = False
+        extra_message = ''
+        if not ctx.branch() == 'default':
+            add_extras = True
+            extra_message += "branch : " + ctx.branch() + "\n"
+
+        renames = []
+        for f in ctx.files():
+            if f not in ctx.manifest():
+                continue
+            rename = ctx.filectx(f).renamed()
+            if rename:
+                renames.append((rename[0], f))
+
+        if renames:
+            add_extras = True
+            for oldfile, newfile in renames:
+                extra_message += "rename : " + oldfile + " => " + newfile + "\n"
+
+        for key, value in extra.iteritems():
+            if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'):
+                continue
+            else:
+                add_extras = True
+                extra_message += "extra : " + key + " : " +  urllib.quote(value) + "\n"
+
+        if add_extras:
+            message += "\n--HG--\n" + extra_message
+
+        return message
+
+    def get_author(self, ctx):
+        # hg authors might not have emails
+        author = ctx.user()
+
+        # check for git author pattern compliance
+        regex = re.compile('^(.*?) \<(.*?)\>(.*)$')
+        a = regex.match(author)
+
+        if a:
+            name = a.group(1)
+            email = a.group(2)
+            if len(a.group(3)) > 0:
+                name += ' ext:(' + urllib.quote(a.group(3)) + ')'
+            author = name + ' <' + email + '>'
+        else:
+            author = author + ' '
+
+        if 'author' in ctx.extra():
+            author = apply_delta(author, ctx.extra()['author'])
+
+        (time, timezone) = ctx.date()
+        date = str(int(time)) + ' ' + self.format_timezone(-timezone)
+
+        return author + ' ' + date
+
+    def get_parents(self, ctx):
+        def is_octopus_part(ctx):
+            return ctx.extra().get('hg-git', None) in ('octopus', 'octopus-done')
+
+        parents = []
+        if ctx.extra().get('hg-git', None) == 'octopus-done':
+            # implode octopus parents
+            part = ctx
+            while is_octopus_part(part):
+                (p1, p2) = part.parents()
+                assert not is_octopus_part(p1)
+                parents.append(p1)
+                part = p2
+            parents.append(p2)
+        else:
+            parents = ctx.parents()
+
+        return parents

From 12c225424e119162e25edb8f7737aff8b06c583c Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:37:06 +0200
Subject: [PATCH 3705/3720] git-remote-hg: add hgexport, an hg-fast-export
 equivalent

This class will be used by git-remote-hg to do the heavy lifting.
---
 git_remote_helpers/hg/hgexport.py | 280 ++++++++++++++++++++++++++++++
 1 file changed, 280 insertions(+)
 create mode 100644 git_remote_helpers/hg/hgexport.py

diff --git a/git_remote_helpers/hg/hgexport.py b/git_remote_helpers/hg/hgexport.py
new file mode 100644
index 0000000000..8a255a45d2
--- /dev/null
+++ b/git_remote_helpers/hg/hgexport.py
@@ -0,0 +1,280 @@
+import binascii
+import os.path
+import sys
+
+
+LF = '\n'
+SP = ' '
+
+
+class HgExportGenerator(object):
+    def __init__(self, repo):
+        self.git_hg = repo.git_hg
+        self.repo = repo
+        self.prefix = repo.prefix
+        self.nullref = "0" * 40
+        self.next_id = 0
+        self.mapping = {}
+        self.debugging = True
+
+    def nextid(self):
+        self.next_id += 1
+        return self.next_id
+
+    def tohex(self, binhex):
+        return binascii.hexlify(binhex)
+
+    def mode(self, fctx):
+        flags = fctx.flags()
+
+        if 'l' in flags:
+          mode = '120000'
+        elif 'x' in flags:
+          mode = '100755'
+        else:
+          mode = '100644'
+
+        return mode
+
+    def parents(self, parents):
+        parents = [self.tohex(i.node()) for i in parents]
+        parents = [i for i in parents if i != self.nullref]
+        assert all(i in self.mapping for i in parents)
+        parents = [':%d' % self.mapping[i] for i in parents]
+
+        return parents
+
+    def ref(self, ctx):
+        return self.prefix + ctx.branch()
+
+    def write(self, *args):
+        msg = ''.join([str(i) for i in args])
+        sys.stdout.write(msg)
+
+    def debug(self, msg):
+        assert LF not in msg
+        self.write('#', SP, msg, LF)
+
+    def feature(self, feature, value=None):
+        if value:
+            self.write('feature', SP, feature, '=', value, LF)
+        else:
+            self.write('feature', SP, feature, LF)
+
+    def option(self, option, value=None):
+        if value:
+            self.write('option', SP, option, '=', value, LF)
+        else:
+            self.write('option', SP, option, LF)
+
+    def option_quiet(self):
+        self.option('quiet')
+
+    def feature_relative_marks(self):
+        self.feature('relative-marks')
+
+    def feature_export_marks(self, marks):
+        self.feature('export-marks', marks)
+
+    def feature_import_marks(self, marks):
+        self.feature('import-marks', marks)
+
+    def feature_force(self):
+        self.feature('force')
+
+    def progress(self, message):
+        self.write('progress', SP, message, LF)
+
+    def write_data(self, data):
+        count = len(data)
+        self.write('data', SP, count, LF)
+        self.write(data, LF)
+
+    def write_mark(self, idnum):
+        self.write('mark', SP, ':', idnum, LF)
+
+    def write_blob(self, data, idnum):
+        self.write('blob', LF)
+        self.write_mark(idnum)
+        self.write_data(data)
+
+    def write_file(self, ctx, file, idnum):
+        fctx = ctx.filectx(file)
+        data = fctx.data()
+
+        self.write_blob(data, idnum)
+
+    def write_commit(self, ref):
+        self.write('commit', SP, ref, LF)
+
+    def write_author(self, author):
+        self.write('author', SP, author, LF)
+
+    def write_committer(self, committer):
+        self.write('committer', SP, committer, LF)
+
+    def write_from(self, parent):
+        self.write('from', SP, parent, LF)
+
+    def write_merge(self, parent):
+        self.write('merge', SP, parent, LF)
+
+    def write_reset(self, ref, idnum):
+        self.write('reset', SP, ref, LF)
+        self.write('from', SP, ':', idnum, LF)
+
+    def write_parents(self, parents):
+        parents = self.parents(parents)
+
+        # first commit
+        if not parents:
+            return
+
+        parent = parents[0]
+
+        self.write_from(parent)
+
+        for parent in parents[1:]:
+            self.write_merge(parent)
+
+    def write_filedeleteall(self):
+        self.write('deleteall', LF)
+
+    def write_filedelete(self, ctx, name):
+        self.write('D', SP, name, LF)
+
+    def write_filemodify_mark(self, mode, name, mark):
+        self.write('M', SP, mode, SP, ':', mark, SP, name, LF)
+
+    def write_filemodify_inline(self, mode, name, data):
+        self.write('M', SP, mode, SP, 'inline', SP, name, LF)
+        self.write_data(data)
+
+    def write_filemodify(self, ctx, name):
+        fctx = ctx.filectx(name)
+        man = ctx.manifest()
+        nodesha = man[name]
+        hash = self.tohex(nodesha)
+        mode = self.mode(fctx)
+
+        if hash in self.mapping:
+            mark = self.mapping[hash]
+            self.write_filemodify_mark(mode, name, mark)
+        else:
+            data = fctx.data()
+            self.write_filemodify_inline(mode, name, data)
+
+    def write_files(self, ctx):
+        man = ctx.manifest()
+
+        if len(ctx.parents()) == 2:
+            self.write_filedeleteall()
+            for name in man:
+                self.write_filemodify(ctx, name)
+        else:
+            for name in ctx.files():
+                # file got deleted
+                if name not in man:
+                    self.write_filedelete(ctx, name)
+                else:
+                    self.write_filemodify(ctx, name)
+
+    def export_files(self, ctx):
+        man = ctx.manifest()
+
+        for name in [i for i in ctx.files() if i in man]:
+            idnum = self.nextid()
+            nodesha = man[name]
+            hash = self.tohex(nodesha)
+
+            self.write_file(ctx, name, idnum)
+            self.mapping[hash] = idnum
+
+    def export_commit(self, ctx, ref, idnum, msg, parents):
+        author = self.git_hg.get_author(ctx)
+        committer = self.git_hg.get_committer(ctx)
+        committer = committer if committer else author
+
+        self.debug('exporting commit')
+        self.write_commit(ref)
+        self.write_mark(idnum)
+        self.write_author(author)
+        self.write_committer(committer)
+        self.write_data(msg)
+        self.write_parents(parents)
+        self.write_files(ctx)
+        self.debug('commit exported')
+
+    def export_revision(self, ctx):
+        nodesha = ctx.node()
+        hash = self.tohex(nodesha)
+
+        if hash in self.mapping:
+            return False
+
+        self.export_files(ctx)
+
+        idnum = self.nextid()
+
+        ref = self.ref(ctx)
+        msg = self.git_hg.get_message(ctx)
+        parents = self.git_hg.get_parents(ctx)
+
+        self.export_commit(ctx, ref, idnum, msg, parents)
+        self.mapping[hash] = idnum
+
+        return True
+
+    def export_branch(self, name, rev):
+        ctx = self.repo.changectx(rev)
+        nodesha = ctx.node()
+        hash = self.tohex(nodesha)
+        idnum = self.mapping[hash]
+
+        ref = self.prefix + name
+
+        self.write_reset(ref, idnum)
+
+    def export_repo(self, refs):
+        self.option_quiet()
+        self.feature_force()
+
+        exported = printed = False
+
+        for rev in self.repo.changelog:
+            ctx = self.repo.changectx(rev)
+            exported = self.export_revision(ctx) or exported
+
+            if (exported and not printed) or (exported and rev%1000 == 0):
+                self.progress("Exported revision %d.\n" % rev)
+                printed = True
+
+    def write_marks(self, base):
+        dirname = self.repo.get_base_path(base)
+        path = os.path.join(dirname, 'hg.marks')
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+        f = open(path, 'w') #self.repo.opener(self.marksfile, 'w', atomictemp=True)
+
+        second = lambda (a, b): b
+
+        for hash, mark in sorted(self.mapping.iteritems(), key=second):
+            f.write(':%d %s\n' % (mark, hash))
+
+        f.close() #f.rename()
+
+    def read_marks(self, base):
+        dirname = self.repo.get_base_path(base)
+        path = os.path.join(dirname, 'hg.marks')
+
+        if not os.path.exists(path):
+            sys.stderr.write("warning: cannot find " + path)
+            return
+
+        f = open(path) #self.repo.opener(self.marksfile)
+
+        marks = [i.strip().split(' ') for i in f.readlines()]
+
+        self.mapping = dict((i[1], int(i[0][1:])) for i in marks)
+        self.next_id = max(self.mapping.values())
+

From 92d64fd7514a0f56386c68dec5321477f20170f5 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:38:43 +0200
Subject: [PATCH 3706/3720] git-remote-hg: add
 GitExporter/GitImporter/NonLocalGit

This is inftrastructure required to implement git-remote-hg.
---
 git_remote_helpers/hg/__init__.py  |  0
 git_remote_helpers/hg/exporter.py  | 29 +++++++++++++++++
 git_remote_helpers/hg/importer.py  | 29 +++++++++++++++++
 git_remote_helpers/hg/non_local.py | 51 ++++++++++++++++++++++++++++++
 git_remote_helpers/hg/util.py      | 14 ++++++++
 5 files changed, 123 insertions(+)
 create mode 100644 git_remote_helpers/hg/__init__.py
 create mode 100644 git_remote_helpers/hg/exporter.py
 create mode 100644 git_remote_helpers/hg/importer.py
 create mode 100644 git_remote_helpers/hg/non_local.py
 create mode 100644 git_remote_helpers/hg/util.py

diff --git a/git_remote_helpers/hg/__init__.py b/git_remote_helpers/hg/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/git_remote_helpers/hg/exporter.py b/git_remote_helpers/hg/exporter.py
new file mode 100644
index 0000000000..20b564dfc0
--- /dev/null
+++ b/git_remote_helpers/hg/exporter.py
@@ -0,0 +1,29 @@
+import binascii
+import os.path
+import sys
+
+from git_remote_helpers.hg import hgexport
+
+
+class GitExporter(object):
+    def __init__(self, repo):
+        self.repo = repo
+
+    def export_repo(self, base, refs):
+        gitmarksfile = os.path.join(self.repo.hash, 'git.marks')
+
+        exporter = hgexport.HgExportGenerator(self.repo)
+
+        exporter.feature_relative_marks()
+        exporter.feature_export_marks(gitmarksfile)
+
+        dirname = self.repo.get_base_path(base)
+        path = os.path.abspath(os.path.join(dirname, 'git.marks'))
+
+        if os.path.exists(path):
+            exporter.feature_import_marks(gitmarksfile)
+            exporter.read_marks(base)
+
+        exporter.export_repo(refs)
+
+        exporter.write_marks(base)
diff --git a/git_remote_helpers/hg/importer.py b/git_remote_helpers/hg/importer.py
new file mode 100644
index 0000000000..ff1eabda02
--- /dev/null
+++ b/git_remote_helpers/hg/importer.py
@@ -0,0 +1,29 @@
+import os.path
+import sys
+
+from git_remote_helpers.hg import hgimport
+from git_remote_helpers.fastimport import processor, parser
+
+
+class GitImporter(object):
+    def __init__(self, repo):
+        self.repo = repo
+
+    def do_import(self, base):
+        sources = ["-"]
+
+        dirname = self.repo.get_base_path(base)
+
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+
+        procc = hgimport.HgImportProcessor(self.repo.ui, self.repo)
+
+        marks_file = os.path.abspath(os.path.join(dirname, 'hg.marks'))
+
+        if os.path.exists(marks_file):
+            procc.load_marksfile(marks_file)
+
+        processor.parseMany(sources, parser.ImportParser, procc)
+
+        procc.write_marksfile(marks_file)
diff --git a/git_remote_helpers/hg/non_local.py b/git_remote_helpers/hg/non_local.py
new file mode 100644
index 0000000000..715bd68cd4
--- /dev/null
+++ b/git_remote_helpers/hg/non_local.py
@@ -0,0 +1,51 @@
+import os
+
+from git_remote_helpers.util import die, warn
+
+class NonLocalHg(object):
+    def __init__(self, repo):
+        self.repo = repo
+        self.hg = repo.hg
+
+    def clone(self, base):
+        path = self.repo.get_base_path(base)
+
+        # already cloned
+        if os.path.exists(os.path.join(path, '.hg')):
+            return path
+
+        if not os.path.exists(path):
+            os.makedirs(path)
+
+        if self.repo.path.endswith(".hg"):
+            from_path = self.repo.path[:-3]
+        else:
+            from_path = self.repo.path
+
+        self.repo.ui.setconfig('ui', 'quiet', "true")
+        self.hg.clone(self.repo.ui, from_path, path, update=False, pull=True)
+
+        return path
+
+    def update(self, base):
+        path = self.repo.get_base_path(base)
+
+        if not os.path.exists(path):
+            die("could not find repo at %s", path)
+
+        repo = self.hg.repository(self.repo.ui, path)
+
+        repo.ui.setconfig('ui', 'quiet', "true")
+        repo.pull(self.repo, heads=self.repo.heads(), force=True)
+
+    def push(self, base):
+        path = self.repo.get_base_path(base)
+
+        if not os.path.exists(path):
+            die("could not find repo at %s", path)
+
+        repo = self.hg.repository(self.repo.ui, path)
+
+        self.repo.ui.setconfig('ui', 'quiet', "true")
+        repo.ui.setconfig('ui', 'quiet', "true")
+        repo.push(self.repo, force=False)
diff --git a/git_remote_helpers/hg/util.py b/git_remote_helpers/hg/util.py
new file mode 100644
index 0000000000..2cd54c1ad0
--- /dev/null
+++ b/git_remote_helpers/hg/util.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+from mercurial import hg
+
+def parseurl(url, heads=[]):
+    url, heads = hg.parseurl(url, heads)
+    if isinstance(heads, tuple) and len(heads) == 2:
+        # hg 1.6 or later
+        _junk, heads = heads
+    if heads:
+        checkout = heads[0]
+    else:
+        checkout = None
+    return url, heads, checkout

From 22f72bb8d00182be3c23ea37be3db93df09bf823 Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Fri, 16 Mar 2012 15:54:33 +0100
Subject: [PATCH 3707/3720] remote-hg: adjust to hg 1.9

hg 1.0 changed the signature of hg.clone(). Adjust to it.

A real fix would need to check the hg version or try/catch.
---
 git_remote_helpers/hg/non_local.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/non_local.py b/git_remote_helpers/hg/non_local.py
index 715bd68cd4..abb7908da0 100644
--- a/git_remote_helpers/hg/non_local.py
+++ b/git_remote_helpers/hg/non_local.py
@@ -23,7 +23,7 @@ class NonLocalHg(object):
             from_path = self.repo.path
 
         self.repo.ui.setconfig('ui', 'quiet', "true")
-        self.hg.clone(self.repo.ui, from_path, path, update=False, pull=True)
+        self.hg.clone(self.repo.ui, {}, from_path, path, update=False, pull=True)
 
         return path
 

From a29ee1b165ece016c663ebe91351f3113673873c Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:38:57 +0200
Subject: [PATCH 3708/3720] git-remote-hg: add the helper

The helper uses the previously added infrastructure.

Signed-off-by: Johannes Schindelin 
---
 .gitignore                  |   1 +
 Makefile                    |   1 +
 git-remote-hg.py            | 101 ++++++++++++++++++++++++++++++++++++
 git_remote_helpers/setup.py |   2 +-
 4 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 git-remote-hg.py

diff --git a/.gitignore b/.gitignore
index bf66648e2c..756356e19c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -121,6 +121,7 @@
 /git-remote-fd
 /git-remote-ext
 /git-remote-testgit
+/git-remote-hg
 /git-repack
 /git-replace
 /git-repo-config
diff --git a/Makefile b/Makefile
index 7fcc056b47..71b49ce9c8 100644
--- a/Makefile
+++ b/Makefile
@@ -452,6 +452,7 @@ SCRIPT_PERL += git-send-email.perl
 SCRIPT_PERL += git-svn.perl
 
 SCRIPT_PYTHON += git-remote-testgit.py
+SCRIPT_PYTHON += git-remote-hg.py
 SCRIPT_PYTHON += git-p4.py
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
diff --git a/git-remote-hg.py b/git-remote-hg.py
new file mode 100644
index 0000000000..fdf61a737d
--- /dev/null
+++ b/git-remote-hg.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+import sys
+import os
+sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
+
+from git_remote_helpers.helper import RemoteHelper
+from git_remote_helpers.util import debug, die, warn
+from git_remote_helpers.hg import util
+from git_remote_helpers.hg.hg import GitHg
+from git_remote_helpers.hg.exporter import GitExporter
+from git_remote_helpers.hg.importer import GitImporter
+from git_remote_helpers.hg.non_local import NonLocalHg
+
+
+class HgRemoteHelper(RemoteHelper):
+    def get_repo(self, alias, url):
+        """Returns a hg.repository object initialized for usage.
+        """
+
+        try:
+            from mercurial import hg, ui
+        except ImportError:
+            die("Mercurial python libraries not installed")
+
+        remote = False
+
+        if url.startswith("remote://"):
+            remote = True
+            url = "file://%s" % url[9:]
+
+        ui = ui.ui()
+        source, revs, checkout = util.parseurl(ui.expandpath(url), ['default'])
+        repo = hg.repository(ui, source)
+        if repo.capable('branchmap'):
+            revs += repo.branchmap().keys()
+            revs = set(revs)
+
+        prefix = 'refs/hg/%s/' % alias
+        debug("prefix: '%s'", prefix)
+
+        repo.marksfile = 'git.marks'
+        repo.hg = hg
+        repo.prefix = prefix
+        repo.revs = revs
+
+        self.setup_repo(repo, alias)
+
+        repo.git_hg = GitHg(warn)
+        repo.exporter = GitExporter(repo)
+        repo.importer = GitImporter(repo)
+        repo.non_local = NonLocalHg(repo)
+
+        repo.is_local = not remote and repo.local()
+
+        return repo
+
+    def local_repo(self, repo, path):
+        """Returns a hg.repository object initalized for usage.
+        """
+
+        local = repo.hg.repository(repo.ui, path)
+
+        self.setup_local_repo(local, repo)
+
+        local.git_hg = repo.git_hg
+        local.hg = repo.hg
+        local.revs = repo.revs
+        local.exporter = GitExporter(local)
+        local.importer = GitImporter(local)
+        local.is_local = repo.is_local
+
+        return local
+
+    def do_list(self, repo, args):
+        """Lists all known references.
+        """
+
+        for ref in repo.revs:
+            debug("? refs/heads/%s", ref)
+            print "? refs/heads/%s" % ref
+
+        debug("@refs/heads/default HEAD")
+        print "@refs/heads/default HEAD"
+
+        print # end list
+
+    def sanitize(self, value):
+        """Cleans up the url.
+        """
+
+        if value.startswith('hg::'):
+            value = value[4:]
+
+        return value
+
+    def get_refs(self, repo, gitdir):
+        return repo.branchmap()
+
+if __name__ == '__main__':
+    sys.exit(HgRemoteHelper().main(sys.argv))
diff --git a/git_remote_helpers/setup.py b/git_remote_helpers/setup.py
index a19c061fdf..4799513c24 100644
--- a/git_remote_helpers/setup.py
+++ b/git_remote_helpers/setup.py
@@ -14,5 +14,5 @@ setup(
     url = 'http://www.git-scm.com/',
     package_dir = {'git_remote_helpers': ''},
     packages = ['git_remote_helpers', 'git_remote_helpers.git',
-                'git_remote_helpers.fastimport'],
+                'git_remote_helpers.fastimport', 'git_remote_helpers.hg'],
 )

From d149b7ae6b55385a7cfcee4acb8f38a8a96fa100 Mon Sep 17 00:00:00 2001
From: Sverre Rabbelier 
Date: Sun, 24 Jul 2011 12:39:03 +0200
Subject: [PATCH 3709/3720] git-remote-hg: add tests

---
 t/t5801-remote-hg.sh | 137 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 137 insertions(+)
 create mode 100755 t/t5801-remote-hg.sh

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
new file mode 100755
index 0000000000..18915ddb8c
--- /dev/null
+++ b/t/t5801-remote-hg.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Sverre Rabbelier
+#
+
+test_description='Test remote-helper import and export commands'
+
+. ./test-lib.sh
+
+if test_have_prereq PYTHON && "$PYTHON_PATH" -c '
+import sys
+if sys.hexversion < 0x02040000:
+    sys.exit(1)
+'
+then
+	:
+else
+	skip_all='skipping git remote-hg tests: requires Python 2.4 or newer'
+	test_done
+fi
+
+# Call cmp with the arguments -x ".hg" -x ".git"  
+
+vcs_cmp () {
+	$DIFF -u -x ".hg" -x ".git" $1 $2
+}
+
+ROOT=$PWD
+
+test_expect_success 'setup repository' '
+	printf "[ui]\nusername = A U Thor " > \
+		${HOME}/.hgrc &&
+	mkdir server &&
+	hg init server/.hg &&
+	hg clone "$ROOT/server" public &&
+	(cd public &&
+	 echo content >file &&
+	 hg add file &&
+	 hg commit -m one &&
+	 hg push)
+'
+
+test_expect_success 'cloning from local repo' '
+	git clone "hg::file://${ROOT}/server" localclone &&
+	vcs_cmp public localclone
+'
+
+test_expect_success 'cloning from remote repo' '
+	git clone "hg::remote://${ROOT}/server" clone &&
+	vcs_cmp public clone
+'
+
+test_expect_success 'create new commit on remote' '
+	(cd public &&
+	 echo content >>file &&
+	 hg commit -A -m two &&
+	 hg push)
+'
+
+test_expect_success 'pulling from local repo' '
+	(cd localclone && git pull) &&
+	vcs_cmp public localclone
+'
+
+test_expect_success 'pulling from remote remote' '
+	(cd clone && git pull) &&
+	vcs_cmp public clone
+'
+
+test_expect_success 'pushing to local empty repo' '
+	hg init localempty &&
+	(cd localclone &&
+	git push --all "hg::file://${ROOT}/localempty") &&
+	(cd localempty &&
+	hg up tip) &&
+	vcs_cmp localclone localempty
+'
+
+test_expect_success 'pushing to remote empty repo' '
+	hg init empty &&
+	(cd localclone &&
+	git push --all "hg::remote://${ROOT}/empty") &&
+	(cd empty &&
+	hg up tip) &&
+	vcs_cmp localclone empty
+'
+
+test_expect_success 'pushing to local repo' '
+	(cd localclone &&
+	echo content >>file &&
+	git commit -a -m three &&
+	git push) &&
+	(cd server &&
+	hg up tip) &&
+	vcs_cmp localclone server
+'
+
+test_expect_success 'synch with changes from localclone' '
+	(cd clone &&
+	 git pull)
+'
+
+test_expect_success 'pushing remote local repo' '
+	(cd clone &&
+	echo content >>file &&
+	git commit -a -m four &&
+	git push) &&
+	(cd server &&
+	hg up tip) &&
+	vcs_cmp clone server
+'
+
+test_expect_success 'creating new branch' '
+	(cd public &&
+	hg branch different-branch &&
+	echo different >> file &&
+	hg commit -m five &&
+	hg push -f)
+'
+
+test_expect_success 'pull in new branch to local repository' '
+	(cd localclone &&
+	git fetch origin default &&
+	test_must_fail git rev-parse -q --verify refs/remotes/origin/different-branch &&
+	git fetch &&
+	git rev-parse --no-revs --verify refs/remotes/origin/different-branch)
+'
+
+test_expect_success 'pull in new branch to remote repository' '
+	(cd clone &&
+	git fetch origin default &&
+	test_must_fail git rev-parse -q --verify refs/remotes/origin/different-branch &&
+	git fetch &&
+	git rev-parse --no-revs --verify refs/remotes/origin/different-branch)
+'
+
+test_done

From a67df35847f8a887c756f5a3e74281bdb87b6345 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Thu, 29 Mar 2012 13:38:43 -0500
Subject: [PATCH 3710/3720] remote-hg: Postel's law dictates we should handle
 Author

We should handle a missing space before the email part of an author ident
gracefully. See for example the icedtea6 repository.

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index 758ba242d8..dd5756d4bb 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -76,7 +76,7 @@ class GitHg(object):
         author = ctx.user()
 
         # check for git author pattern compliance
-        regex = re.compile('^(.*?) \<(.*?)\>(.*)$')
+        regex = re.compile('^(.*?) ?\<(.*?)\>(.*)$')
         a = regex.match(author)
 
         if a:

From 472200fa11cddeeafa93e84b6077a04491bce2de Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 00:27:45 -0500
Subject: [PATCH 3711/3720] remote-hg: another case of Postel's law

This change allows invalid input from Mercurial repositories where the
author is recorded as 'Name ').

With this change, importing http://scelenic.com/hg itself no longer fails
with:

	fatal: Missing > in ident string: Benoit Boissinot
	 1129685868 -0700

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index dd5756d4bb..cdd13fa513 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -76,17 +76,21 @@ class GitHg(object):
         author = ctx.user()
 
         # check for git author pattern compliance
-        regex = re.compile('^(.*?) ?\<(.*?)\>(.*)$')
+        regex = re.compile('^(.*?) ?\<(.*?)(|\>(.*))$')
         a = regex.match(author)
 
         if a:
             name = a.group(1)
             email = a.group(2)
-            if len(a.group(3)) > 0:
-                name += ' ext:(' + urllib.quote(a.group(3)) + ')'
+            extra = a.group(4)
+            if not extra is None and len(extra) > 0:
+                name += ' ext:(' + urllib.quote(extra) + ')'
             author = name + ' <' + email + '>'
         else:
-            author = author + ' '
+            if author.find('<') >= 0:
+                author = author + '>'
+            else:
+                author = author + ' '
 
         if 'author' in ctx.extra():
             author = apply_delta(author, ctx.extra()['author'])

From 0dc6202322cbf8d692a72c39159a63eb63bbe2d9 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 00:56:31 -0500
Subject: [PATCH 3712/3720] remote-hg: handle another funny author line from
 http://scelenic.com/hg

In this case: David Soria Parra  php.net>.

With this last of three Postel patches, remote-hg can import the
Mercurial repository completely.

Signed-off-by: Johannes Schindelin 
---
 git_remote_helpers/hg/hg.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/git_remote_helpers/hg/hg.py b/git_remote_helpers/hg/hg.py
index cdd13fa513..d835ed47e4 100644
--- a/git_remote_helpers/hg/hg.py
+++ b/git_remote_helpers/hg/hg.py
@@ -84,7 +84,13 @@ class GitHg(object):
             email = a.group(2)
             extra = a.group(4)
             if not extra is None and len(extra) > 0:
-                name += ' ext:(' + urllib.quote(extra) + ')'
+                if email.endswith('  ', '.')
+                    extra = extra.replace('>', '')
+                    email = email[:-4] + '@' + extra
+                else:
+                    name += ' ext:(' + urllib.quote(extra) + ')'
             author = name + ' <' + email + '>'
         else:
             if author.find('<') >= 0:

From e3705f658ec38209074169380070a6081bdec65b Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Sat, 7 Apr 2012 02:12:53 -0500
Subject: [PATCH 3713/3720] remote-hg: do not interfer with hg's revs() method

Matt Mackall introduced a revs() method to the localrepo class on Wed
Nov 2 13:37:34 2011 in the commit 'localrepo: add revs helper method'.
It is used when constructing a commit in memory.

If we store the set of revs we want to handle under the same name, it
overrides that method, resulting in an unpleasant 'TypeError: 'set'
object is not callable' whenever we want to push (as we are constructing
commits in memory, then).

So let's work around that by renaming our field to 'revs_' and hope that
upstream Mercurial does not introduce a field of that name, too.

Signed-off-by: Johannes Schindelin 
---
 git-remote-hg.py               | 6 +++---
 git-remote-testgit.py          | 2 +-
 git_remote_helpers/git/repo.py | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/git-remote-hg.py b/git-remote-hg.py
index fdf61a737d..4b619e9c4c 100644
--- a/git-remote-hg.py
+++ b/git-remote-hg.py
@@ -42,7 +42,7 @@ class HgRemoteHelper(RemoteHelper):
         repo.marksfile = 'git.marks'
         repo.hg = hg
         repo.prefix = prefix
-        repo.revs = revs
+        repo.revs_ = revs # must not override repo.revs()
 
         self.setup_repo(repo, alias)
 
@@ -65,7 +65,7 @@ class HgRemoteHelper(RemoteHelper):
 
         local.git_hg = repo.git_hg
         local.hg = repo.hg
-        local.revs = repo.revs
+        local.revs_ = repo.revs_
         local.exporter = GitExporter(local)
         local.importer = GitImporter(local)
         local.is_local = repo.is_local
@@ -76,7 +76,7 @@ class HgRemoteHelper(RemoteHelper):
         """Lists all known references.
         """
 
-        for ref in repo.revs:
+        for ref in repo.revs_:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 
diff --git a/git-remote-testgit.py b/git-remote-testgit.py
index d57c1dc393..740e02b1f3 100644
--- a/git-remote-testgit.py
+++ b/git-remote-testgit.py
@@ -56,7 +56,7 @@ class TestgitRemoteHelper(RemoteHelper):
         head is at clone time.
         """
 
-        for ref in repo.revs:
+        for ref in repo.revs_:
             debug("? refs/heads/%s", ref)
             print "? refs/heads/%s" % ref
 
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
index 4536233868..fa68e47101 100644
--- a/git_remote_helpers/git/repo.py
+++ b/git_remote_helpers/git/repo.py
@@ -61,7 +61,7 @@ class GitRepo(object):
         self.revmap = dict(sanitize(i) for i in output)
         if "HEAD" in self.revmap:
             del self.revmap["HEAD"]
-        self.revs = self.revmap.keys()
+        self.revs_ = self.revmap.keys()
         ofile.close()
 
     def get_head(self):

From 1542f51e1eafc37afe4b1c4fe00c2f42ce98ef0c Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 13:04:35 -0500
Subject: [PATCH 3714/3720] Always auto-gc after calling a fast-import
 transport

After importing anything with fast-import, we should always let the
garbage collector do its job, since the objects are written to disk
inefficiently.

This brings down an initial import of http://selenic.com/hg from about
230 megabytes to about 14.

In the future, we may want to make this configurable on a per-remote
basis, or maybe teach fast-import about it in the first place.

Signed-off-by: Johannes Schindelin 
---
 transport-helper.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index 3b6a9fa53d..5ff0e44a6d 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -12,6 +12,8 @@
 #include "sigchain.h"
 
 static int debug;
+/* TODO: put somewhere sensible, e.g. git_transport_options? */
+static int auto_gc = 1;
 
 struct helper_data {
 	const char *name;
@@ -476,6 +478,12 @@ static int fetch_with_import(struct transport *transport,
 		}
 	}
 	strbuf_release(&buf);
+	if (auto_gc) {
+		const char *argv_gc_auto[] = {
+			"gc", "--auto", "--quiet", NULL,
+		};
+		run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+	}
 	return 0;
 }
 

From 5caafa8f5bfa797da0d018c251bc46d927eaec4e Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Mon, 9 Apr 2012 16:37:57 -0500
Subject: [PATCH 3715/3720] fast-export: report SHA-1 instead of gibberish when
 marks exist already

Cc: Pieter de Bie 
Signed-off-by: Johannes Schindelin 
---
 builtin/fast-export.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 137792d49d..1213155acf 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -644,7 +644,7 @@ static void import_marks(char *input_file)
 			die ("Could not read blob %s", sha1_to_hex(sha1));
 
 		if (object->flags & SHOWN)
-			error("Object %s already has a mark", sha1);
+			error("Object %s already has a mark", sha1_to_hex(sha1));
 
 		mark_object(object, mark);
 		if (last_idnum < mark)

From 2f463713c6a4abd8ebfcad3dfa5d4110e6f3e3d5 Mon Sep 17 00:00:00 2001
From: Michael J Gruber 
Date: Sat, 3 Mar 2012 19:57:22 +0100
Subject: [PATCH 3716/3720] t5801: skip without hg

The tests for remote-hg require hg, so skip them all when there is no
hg available.
---
 t/t5801-remote-hg.sh | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
index 18915ddb8c..2e68372d59 100755
--- a/t/t5801-remote-hg.sh
+++ b/t/t5801-remote-hg.sh
@@ -19,6 +19,12 @@ else
 	test_done
 fi
 
+if ! type hg >/dev/null 2>&1
+then
+	skip_all='skipping git remote-hg tests: requires hg'
+	test_done
+fi
+
 # Call cmp with the arguments -x ".hg" -x ".git"  
 
 vcs_cmp () {

From 6cd0c5d1b3b8e393bf11f87109417d2684811f29 Mon Sep 17 00:00:00 2001
From: Olivier Refalo 
Date: Wed, 9 May 2012 12:35:02 -0300
Subject: [PATCH 3717/3720] fix build: compat/mingw.c:1236: error: conflicting
 types for 'mingw_execv' compat/../compat/mingw.h:294: note: previous
 declaration of 'mingw_execv' was here make: *** [compat/mingw.o] Error 1

---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 8c46a5c76b..4b80acafc8 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -291,7 +291,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 		     int fhin, int fhout, int fherr);
 int mingw_execvp(const char *cmd, char *const *argv);
 #define execvp mingw_execvp
-int mingw_execv(const char *cmd, char *const *argv);
+void mingw_execv(const char *cmd, char *const *argv);
 #define execv mingw_execv
 
 static inline unsigned int git_ntohl(unsigned int x)

From 967b1b84bbdc17a969471e56fe330ca9d9627e88 Mon Sep 17 00:00:00 2001
From: Olivier Refalo 
Date: Wed, 9 May 2012 13:48:46 -0300
Subject: [PATCH 3718/3720] POSIX style 1/2

---
 compat/mingw.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/mingw.h b/compat/mingw.h
index 4b80acafc8..8c46a5c76b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -291,7 +291,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 		     int fhin, int fhout, int fherr);
 int mingw_execvp(const char *cmd, char *const *argv);
 #define execvp mingw_execvp
-void mingw_execv(const char *cmd, char *const *argv);
+int mingw_execv(const char *cmd, char *const *argv);
 #define execv mingw_execv
 
 static inline unsigned int git_ntohl(unsigned int x)

From cb9077b04953562eef1a261c2be96352ca0c8759 Mon Sep 17 00:00:00 2001
From: Olivier Refalo 
Date: Wed, 9 May 2012 13:50:07 -0300
Subject: [PATCH 3719/3720] POSIX style 2/2

---
 compat/mingw.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 86c3fe7bdc..6025ac5eaf 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1233,7 +1233,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
 	return pid;
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
+int mingw_execv(const char *cmd, char *const *argv)
 {
 	/* check if git_command is a shell script */
 	if (!try_shell_exec(cmd, argv)) {
@@ -1241,11 +1241,12 @@ void mingw_execv(const char *cmd, char *const *argv)
 
 		pid = mingw_spawnv(cmd, (const char **)argv, 0);
 		if (pid < 0)
-			return;
+			return -1;
 		if (waitpid(pid, &status, 0) < 0)
 			status = 255;
 		exit(status);
 	}
+	return -1;
 }
 
 int mingw_execvp(const char *cmd, char *const *argv)

From ec1752b4178825156201c9e5dffac52f215438ec Mon Sep 17 00:00:00 2001
From: Johannes Schindelin 
Date: Fri, 11 May 2012 21:11:45 -0500
Subject: [PATCH 3720/3720] Fix invalid call to dd(1)

t4012 assumed that it is okay to seek beyond the end of stdin. It is not,
and leads to an access violation (Windows speak for: segmentation fault)
with MinGW's dd.exe iff run in non-verbose mode.

Further, for some reason 'echo X | dd bs=1k seek=1' resulted in 2050 bytes
in this developer's setup instead of 1026.

So let's use a valid technique to generate 1024 NULs followed by X and a
line feed: a good ole' Perl script.

This patch is dedicated to Randal "Merlyn" Schwartz.

Signed-off-by: Johannes Schindelin 
---
 t/t4012-diff-binary.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 8b4e80de96..40b4530578 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -113,7 +113,7 @@ cat >expect < binfile &&
 	git add binfile &&
 	i=0 &&
 	while test $i -lt 10000; do